1 /* 2 * Copyright (C) 2022 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 17 package com.android.server.uwb.secure; 18 19 import static com.android.server.uwb.secure.csml.DispatchResponse.NOTIFICATION_EVENT_ID_SECURE_SESSION_ABORTED; 20 21 import android.os.Looper; 22 import android.util.Log; 23 24 import androidx.annotation.NonNull; 25 26 import com.android.server.uwb.pm.RunningProfileSessionInfo; 27 import com.android.server.uwb.secure.csml.DispatchResponse; 28 import com.android.server.uwb.secure.iso7816.StatusWord; 29 30 import java.util.Optional; 31 32 /** 33 * Dynamic STS session for responder. 34 */ 35 public abstract class ResponderSession extends SecureSession { 36 private static final String LOG_TAG = "ResponderSession"; 37 ResponderSession( @onNull Looper workLooper, @NonNull FiRaSecureChannel fiRaSecureChannel, @NonNull Callback sessionCallback, @NonNull RunningProfileSessionInfo runningProfileSessionInfo)38 ResponderSession( 39 @NonNull Looper workLooper, 40 @NonNull FiRaSecureChannel fiRaSecureChannel, 41 @NonNull Callback sessionCallback, 42 @NonNull RunningProfileSessionInfo runningProfileSessionInfo) { 43 super(workLooper, fiRaSecureChannel, sessionCallback, runningProfileSessionInfo); 44 } 45 46 /** 47 * Process the dispatch response if it is expected. 48 * @return true if the response is expected and processed, false otherwise. 49 */ onDispatchResponseReceived( @onNull DispatchResponse dispatchResponse)50 protected abstract boolean onDispatchResponseReceived( 51 @NonNull DispatchResponse dispatchResponse); 52 onUnsolicitedDataToHostReceived(@onNull byte[] data)53 protected abstract void onUnsolicitedDataToHostReceived(@NonNull byte[] data); 54 55 @Override handleDispatchCommandFailure()56 protected final void handleDispatchCommandFailure() { 57 // can do nothing for responder. ignore it. 58 logw("a dispatch command wasn't handled correctly."); 59 } 60 61 @Override handleDispatchResponse(@onNull DispatchResponse dispatchResponse)62 protected final void handleDispatchResponse(@NonNull DispatchResponse dispatchResponse) { 63 if (!dispatchResponse.statusWord.equals(StatusWord.SW_NO_ERROR)) { 64 logw("Wrong DispatchResponse sw: " + dispatchResponse.statusWord); 65 terminateSession(); 66 mSessionCallback.onSessionAborted(); 67 return; 68 } 69 // once session is aborted, nothing else in the response. 70 for (DispatchResponse.Notification notification : dispatchResponse.notifications) { 71 switch (notification.notificationEventId) { 72 case NOTIFICATION_EVENT_ID_SECURE_SESSION_ABORTED: 73 mFiRaSecureChannel.cleanUpTerminatedOrAbortedSession(); 74 mSessionCallback.onSessionAborted(); 75 return; 76 default: 77 logw("unhandled notification from dispatch response: " 78 + notification.notificationEventId); 79 break; 80 } 81 } 82 83 Optional<DispatchResponse.OutboundData> outboundData = dispatchResponse.getOutboundData(); 84 if (outboundData.isPresent() 85 && outboundData.get().target == DispatchResponse.OUTBOUND_TARGET_REMOTE) { 86 logd("send response back to remote."); 87 mFiRaSecureChannel.sendRawDataToRemote(outboundData.get().data); 88 } 89 if (onDispatchResponseReceived(dispatchResponse)) { 90 return; 91 } 92 93 if (outboundData.isPresent() 94 && outboundData.get().target == DispatchResponse.OUTBOUND_TARGET_HOST) { 95 onUnsolicitedDataToHostReceived(outboundData.get().data); 96 } 97 } 98 99 @Override handleFiRaSecureChannelEstablished()100 protected void handleFiRaSecureChannelEstablished() { 101 // do nothing, wait for request from initiator. 102 // TODO: add a time out protection 103 } 104 105 @Override terminateSession()106 public final void terminateSession() { 107 mWorkHandler.post(() -> mFiRaSecureChannel.terminateLocally()); 108 } 109 logd(@onNull String dbgMsg)110 private void logd(@NonNull String dbgMsg) { 111 Log.d(LOG_TAG, dbgMsg); 112 } 113 logw(@onNull String dbgMsg)114 private void logw(@NonNull String dbgMsg) { 115 Log.w(LOG_TAG, dbgMsg); 116 } 117 } 118