blob: 5969d69e4ac60eac08e60b2c333b20c72ddb90cc [file] [log] [blame]
nxpandroid64fd68c2015-09-23 16:45:15 +05301/*
2 * Copyright (C) 2011 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 */
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +053016
nxf500513a018e72019-04-23 17:11:41 +053017/******************************************************************************
18*
19* The original Work has been changed by NXP.
20*
21* Licensed under the Apache License, Version 2.0 (the "License");
22* you may not use this file except in compliance with the License.
23* You may obtain a copy of the License at
24*
25* http://www.apache.org/licenses/LICENSE-2.0
26*
27* Unless required by applicable law or agreed to in writing, software
28* distributed under the License is distributed on an "AS IS" BASIS,
29* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30* See the License for the specific language governing permissions and
31* limitations under the License.
32*
Ganesh Deva1ad7d6f2019-06-17 11:46:02 +053033* Copyright 2018 NXP
nxf500513a018e72019-04-23 17:11:41 +053034*
35******************************************************************************/
nxpandroid64fd68c2015-09-23 16:45:15 +053036package com.android.nfc.snep;
37
38import com.android.nfc.DeviceHost.LlcpSocket;
39import com.android.nfc.NfcService;
40import com.android.nfc.sneptest.DtaSnepClient;
nxpandroida9a68ba2016-01-14 21:12:17 +053041import com.android.nfc.sneptest.ExtDtaSnepServer;
nxpandroid64fd68c2015-09-23 16:45:15 +053042
43import android.nfc.FormatException;
44import android.util.Log;
45
46import java.io.ByteArrayInputStream;
47import java.io.ByteArrayOutputStream;
48import java.io.DataInputStream;
49import java.io.IOException;
50import java.util.Arrays;
51
52public class SnepMessenger {
53 private static final String TAG = "SnepMessenger";
nxf500513a018e72019-04-23 17:11:41 +053054 private static final boolean DBG = true;
nxpandroid64fd68c2015-09-23 16:45:15 +053055 private static final int HEADER_LENGTH = 6;
56 final LlcpSocket mSocket;
57 final int mFragmentLength;
58 final boolean mIsClient;
59
60 public SnepMessenger(boolean isClient, LlcpSocket socket, int fragmentLength) {
61 mSocket = socket;
62 mFragmentLength = fragmentLength;
63 mIsClient = isClient;
64 }
65
66 public void sendMessage(SnepMessage msg) throws IOException {
67 byte[] buffer = msg.toByteArray();
68 byte remoteContinue;
69 if (mIsClient) {
70 remoteContinue = SnepMessage.RESPONSE_CONTINUE;
71 } else {
72 remoteContinue = SnepMessage.REQUEST_CONTINUE;
73 }
74 if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message");
75
76 // Send first fragment
77 int length = Math.min(buffer.length, mFragmentLength);
78 byte[] tmpBuffer = Arrays.copyOfRange(buffer, 0, length);
79 if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
80 mSocket.send(tmpBuffer);
81
82 if (length == buffer.length) {
83 return;
84 }
85
86 // Look for Continue or Reject from peer.
87 int offset = length;
88 byte[] responseBytes = new byte[HEADER_LENGTH];
89 mSocket.receive(responseBytes);
90 SnepMessage snepResponse;
91 try {
92 snepResponse = SnepMessage.fromByteArray(responseBytes);
93 } catch (FormatException e) {
94 throw new IOException("Invalid SNEP message", e);
95 }
96
97 if (DBG) Log.d(TAG, "Got response from first fragment: " + snepResponse.getField());
98 if (snepResponse.getField() != remoteContinue) {
99 throw new IOException("Invalid response from server (" +
100 snepResponse.getField() + ")");
101 }
102 // Look for wrong/invalid request or response from peer
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530103 if (NfcService.sIsDtaMode) {
104 if (mIsClient && (DtaSnepClient.mTestCaseId == 6)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530105 length = Math.min(buffer.length - offset, mFragmentLength);
106 tmpBuffer = Arrays.copyOfRange(buffer, offset, offset + length);
107 if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
108 mSocket.send(tmpBuffer);
109 offset += length;
110
111 mSocket.receive(responseBytes);
112
113 try {
114 snepResponse = SnepMessage.fromByteArray(responseBytes);
115 } catch (FormatException e) {
116 throw new IOException("Invalid SNEP message", e);
117 }
118 if (DBG) Log.d(TAG, "Got response from second fragment: " + snepResponse.getField());
119 if (snepResponse.getField() == remoteContinue) {
120 close();
121 return;
122 }
123 }
124 }
125
126 // Send remaining fragments.
127 while (offset < buffer.length) {
128 length = Math.min(buffer.length - offset, mFragmentLength);
129 tmpBuffer = Arrays.copyOfRange(buffer, offset, offset + length);
130 if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
131 mSocket.send(tmpBuffer);
132
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530133 if (NfcService.sIsDtaMode) {
134 if (!mIsClient && ExtDtaSnepServer.mTestCaseId == 0x01) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530135 mSocket.receive(responseBytes);
136 try {
137 snepResponse = SnepMessage.fromByteArray(responseBytes);
138 } catch (FormatException e) {
139 throw new IOException("Invalid SNEP message", e);
140 }
141 if (DBG) Log.d(TAG, "Got continue response after second fragment: and now disconnecting..." + snepResponse.getField());
142 if (snepResponse.getField() == remoteContinue) {
143 close();
144 return;
145 }
146 }
147 }
148
149 offset += length;
150 }
151 }
152
153 public SnepMessage getMessage() throws IOException, SnepException {
154 ByteArrayOutputStream buffer = new ByteArrayOutputStream(mFragmentLength);
155 byte[] partial = new byte[mFragmentLength];
156 int size;
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530157 int requestSize = 0;
nxpandroid64fd68c2015-09-23 16:45:15 +0530158 int readSize = 0;
159 byte requestVersion = 0;
160 byte requestField = 0; // for DTA Mode
nxpandroid64fd68c2015-09-23 16:45:15 +0530161 boolean doneReading = false;
162 byte fieldContinue;
163 byte fieldReject;
164 if (mIsClient) {
165 fieldContinue = SnepMessage.REQUEST_CONTINUE;
166 fieldReject = SnepMessage.REQUEST_REJECT;
167 } else {
168 fieldContinue = SnepMessage.RESPONSE_CONTINUE;
169 fieldReject = SnepMessage.RESPONSE_REJECT;
170 }
171
172 size = mSocket.receive(partial);
173 if (DBG) Log.d(TAG, "read " + size + " bytes");
174 if (size < 0) {
175 try {
176 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
177 } catch (IOException e) {
178 // Ignore
179 }
180 throw new IOException("Error reading SNEP message.");
181 } else if (size < HEADER_LENGTH) {
182 try {
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530183 if (NfcService.sIsDtaMode && mIsClient) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530184 if (DBG) Log.d(TAG, "Invalid header length");
185 close();
186 } else {
187 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
188
189 }
190 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
191 } catch (IOException e) {
192 // Ignore
193 }
194 throw new IOException("Invalid fragment from sender.");
195 } else {
196 readSize = size - HEADER_LENGTH;
197 buffer.write(partial, 0, size);
198 }
199
200 DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(partial));
201 requestVersion = dataIn.readByte();
202 requestField = dataIn.readByte();
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530203 requestSize = dataIn.readInt();
nxpandroid64fd68c2015-09-23 16:45:15 +0530204
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530205 if (DBG) Log.d(TAG, "read " + readSize + " of " + requestSize);
nxpandroid64fd68c2015-09-23 16:45:15 +0530206
207 if (((requestVersion & 0xF0) >> 4) != SnepMessage.VERSION_MAJOR) {
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530208 if (NfcService.sIsDtaMode) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530209 sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_UNSUPPORTED_VERSION));
210 close();
211 } else {
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530212 if (NfcService.sIsDtaMode) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530213 sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_UNSUPPORTED_VERSION));
214 close();
215 } else {
216 // Invalid protocol version; treat message as complete.
217 return new SnepMessage(requestVersion, requestField, 0, 0, null);
218 }
219 }
220
221 }
222
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530223 if (NfcService.sIsDtaMode) {
nxf38293cc40ef22018-02-13 11:27:30 +0530224 if (!mIsClient && (requestField == SnepMessage.RESPONSE_CONTINUE || // added for TC_S_BIT_B1_01_X
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530225 requestField == SnepMessage.RESPONSE_SUCCESS ||
nxf38293cc40ef22018-02-13 11:27:30 +0530226 requestField == SnepMessage.RESPONSE_NOT_FOUND)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530227 if (DBG) Log.d(TAG, "errorneous response received, disconnecting client");
228 close();
229 }
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530230 if (!mIsClient && requestField == SnepMessage.REQUEST_RFU) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530231 if (DBG) Log.d(TAG, "unknown request received, disconnecting client");
232 sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_BAD_REQUEST));
233 close();
nxpandroid64fd68c2015-09-23 16:45:15 +0530234 }
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530235 // added for TC_C_BIT_BI_01_0
236 if (mIsClient && requestField == SnepMessage.REQUEST_PUT) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530237 if (DBG) Log.d(TAG, "errorneous PUT request received, disconnecting from server");
238 close();
239 }
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530240 // added for TC_C_GET_BV_03
241 if (mIsClient && (requestSize > SnepMessage.MAL_IUT)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530242 if (DBG) Log.d(TAG, "responding reject");
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530243 return new SnepMessage(requestVersion, requestField, requestSize, 0, null);
nxpandroid64fd68c2015-09-23 16:45:15 +0530244 }
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530245 //added for TC_S_ACC_BV_05_0&1 and TC_S_ACC_BV_06_0&1
246 if (!mIsClient && ((requestSize > SnepMessage.MAL_IUT) ||
247 requestSize == SnepMessage.MAL)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530248 if (DBG) Log.d(TAG, "responding reject");
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530249 return new SnepMessage(requestVersion, requestField, requestSize, 0, null);
nxpandroid64fd68c2015-09-23 16:45:15 +0530250 }
251 }
252
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530253 if (requestSize > readSize) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530254 if (DBG) Log.d(TAG, "requesting continuation");
255 mSocket.send(SnepMessage.getMessage(fieldContinue).toByteArray());
256 } else {
257 doneReading = true;
258 }
259
260 // Remaining fragments
261 while (!doneReading) {
262 try {
263 size = mSocket.receive(partial);
264 if (DBG) Log.d(TAG, "read " + size + " bytes");
265 if (size < 0) {
266 try {
267 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
268 } catch (IOException e) {
269 // Ignore
270 }
271 throw new IOException();
272 } else {
273 readSize += size;
274 buffer.write(partial, 0, size);
Bhupendra Pawar9f0c8382018-01-11 17:05:27 +0530275 if (readSize == requestSize) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530276 doneReading = true;
277 }
278 }
279 } catch (IOException e) {
280 try {
281 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
282 } catch (IOException e2) {
283 // Ignore
284 }
285 throw e;
286 }
287 }
288
289 // Build NDEF message set from the stream
290 try {
291 return SnepMessage.fromByteArray(buffer.toByteArray());
292 } catch (FormatException e) {
293 Log.e(TAG, "Badly formatted NDEF message, ignoring", e);
294 throw new SnepException(e);
295 }
296 }
297
298 public void close() throws IOException {
299 mSocket.close();
300 }
301}