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.csml; 18 19 import static com.android.server.uwb.secure.csml.SecureRangingInfo.SECURE_RANGING_INFO_TAG; 20 21 import android.util.Log; 22 23 import androidx.annotation.NonNull; 24 25 import com.android.server.uwb.params.TlvBuffer; 26 import com.android.server.uwb.params.TlvDecoderBuffer; 27 28 import java.nio.ByteBuffer; 29 import java.util.Arrays; 30 import java.util.Optional; 31 32 import javax.annotation.Nullable; 33 34 /** 35 * The session data used to config UWB session, see CSML 8.5.3.3. 36 */ 37 public class SessionData { 38 39 public static final String TAG = SessionData.class.getSimpleName(); 40 41 public static final int UWB_SESSION_DATA_VERSION_HEADER = 0x80; 42 public static int UWB_SESSION_DATA_VERSION_MINOR = 1; 43 public static int UWB_SESSION_DATA_VERSION_MAJOR = 1; 44 public static int UWB_SESSION_DATA_VERSION_MINOR_CURRENT = 1; 45 public static int UWB_SESSION_DATA_VERSION_MAJOR_CURRENT = 1; 46 public static int UWB_SESSION_ID = 0x81; 47 public static int UWB_SUB_SESSION_ID = 0x82; 48 49 public static final int CONFIGURATION_PARAMS = 0xA3; 50 public Optional<ConfigurationParams> mConfigurationParams; 51 public Optional<SecureRangingInfo> mSecureRangingInfo; 52 public static int SESSION_DATA_COUNT_MAX = 8; 53 54 public final int mSessionId; 55 public final Optional<Integer> mSubSessionId; 56 SessionData(int sessionId, Optional<Integer> subSessionId, Optional<ConfigurationParams> configurationParams, Optional<SecureRangingInfo> secureRangingInfo)57 private SessionData(int sessionId, Optional<Integer> subSessionId, 58 Optional<ConfigurationParams> configurationParams, 59 Optional<SecureRangingInfo> secureRangingInfo) { 60 mSessionId = sessionId; 61 mSubSessionId = subSessionId; 62 mConfigurationParams = configurationParams; 63 mSecureRangingInfo = secureRangingInfo; 64 } 65 66 /** 67 * Convert to raw data represented as TLV according to CSML 8.5.3.3. 68 */ 69 @NonNull toBytes()70 public byte[] toBytes() { 71 TlvBuffer.Builder sessionDataBuilder = new TlvBuffer.Builder() 72 .putByteArray(UWB_SESSION_DATA_VERSION_HEADER, new byte[]{ 73 (byte) UWB_SESSION_DATA_VERSION_MAJOR_CURRENT, 74 (byte) UWB_SESSION_DATA_VERSION_MINOR_CURRENT}); 75 76 sessionDataBuilder.putByteArray(UWB_SESSION_ID, ByteBuffer.allocate(4).putInt( 77 mSessionId).array()); 78 mSubSessionId.ifPresent( 79 integer -> sessionDataBuilder.putByteArray(UWB_SUB_SESSION_ID, ByteBuffer.allocate( 80 4).putInt( 81 integer).array())); 82 mConfigurationParams.ifPresent( 83 configurationParams -> sessionDataBuilder.putByteArray(CONFIGURATION_PARAMS, 84 configurationParams.toBytes())); 85 mSecureRangingInfo.ifPresent( 86 secureRangingInfo -> sessionDataBuilder.putByteArray( 87 SECURE_RANGING_INFO_TAG, secureRangingInfo.toBytes())); 88 89 return sessionDataBuilder.build().getByteArray(); 90 } 91 isPresent(TlvDecoderBuffer tlvDecoderBuffer, int tagType)92 private static boolean isPresent(TlvDecoderBuffer tlvDecoderBuffer, int tagType) { 93 try { 94 tlvDecoderBuffer.getByte(tagType); 95 } catch (IllegalArgumentException e) { 96 try { 97 tlvDecoderBuffer.getByteArray(tagType); 98 } catch (IllegalArgumentException e1) { 99 return false; 100 } 101 } 102 return true; 103 } 104 105 /** Converts {@link SessionData} from the TLV data payload. */ 106 @Nullable fromBytes(@onNull byte[] data)107 public static SessionData fromBytes(@NonNull byte[] data) { 108 TlvDecoderBuffer tlvs = new TlvDecoderBuffer(data, SESSION_DATA_COUNT_MAX); 109 tlvs.parse(); 110 111 if (isPresent(tlvs, UWB_SESSION_DATA_VERSION_HEADER)) { 112 byte[] sessionDataVersion = tlvs.getByteArray(UWB_SESSION_DATA_VERSION_HEADER); 113 if (sessionDataVersion.length == 2 && versionCheck(sessionDataVersion)) { 114 Builder sessionDataBuilder = new Builder(); 115 if (isPresent(tlvs, UWB_SESSION_ID)) { 116 sessionDataBuilder.setSessionId( 117 ByteBuffer.wrap(tlvs.getByteArray(UWB_SESSION_ID)).getInt()); 118 } 119 if (isPresent(tlvs, UWB_SUB_SESSION_ID)) { 120 sessionDataBuilder.setSubSessionId( 121 ByteBuffer.wrap(tlvs.getByteArray(UWB_SUB_SESSION_ID)).getInt()); 122 } 123 if (isPresent(tlvs, CONFIGURATION_PARAMS)) { 124 byte[] configurationParams = tlvs.getByteArray(CONFIGURATION_PARAMS); 125 sessionDataBuilder.setConfigParams( 126 ConfigurationParams.fromBytes(configurationParams)); 127 } 128 if (isPresent(tlvs, SECURE_RANGING_INFO_TAG)) { 129 byte[] secureRangingInfo = tlvs.getByteArray(SECURE_RANGING_INFO_TAG); 130 sessionDataBuilder.setSecureRangingInfo( 131 SecureRangingInfo.fromBytes(secureRangingInfo)); 132 } 133 return sessionDataBuilder.build(); 134 } 135 Log.e(TAG, "UWB_SESSION_DATA_VERSION " + Arrays.toString(sessionDataVersion) 136 + " Not supported"); 137 } else { 138 Log.e(TAG, "Controlee info version is not included. Failure !"); 139 } 140 return null; 141 } 142 versionCheck(byte[] sessionDataVersion)143 private static boolean versionCheck(byte[] sessionDataVersion) { 144 return sessionDataVersion[0] == UWB_SESSION_DATA_VERSION_MAJOR 145 && sessionDataVersion[1] == UWB_SESSION_DATA_VERSION_MINOR; 146 } 147 148 /** Builder */ 149 public static class Builder { 150 private int mSessionId; 151 private Optional<Integer> mSubSessionId = Optional.empty(); 152 private Optional<ConfigurationParams> mConfigurationParams = Optional.empty(); 153 private Optional<SecureRangingInfo> mSecureRangingInfo = Optional.empty(); 154 Builder()155 public Builder() { 156 } 157 setSessionId(int sessionId)158 SessionData.Builder setSessionId(int sessionId) { 159 mSessionId = sessionId; 160 return this; 161 } 162 setSubSessionId(int subSessionId)163 SessionData.Builder setSubSessionId(int subSessionId) { 164 mSubSessionId = Optional.of(subSessionId); 165 return this; 166 } 167 168 @NonNull setConfigParams( @onNull ConfigurationParams configurationParams)169 SessionData.Builder setConfigParams( 170 @NonNull ConfigurationParams configurationParams) { 171 mConfigurationParams = Optional.of(configurationParams); 172 return this; 173 } 174 175 @NonNull setSecureRangingInfo(@onNull SecureRangingInfo secureRangingInfo)176 SessionData.Builder setSecureRangingInfo(@NonNull SecureRangingInfo secureRangingInfo) { 177 mSecureRangingInfo = Optional.of(secureRangingInfo); 178 return this; 179 } 180 181 @NonNull build()182 SessionData build() { 183 return new SessionData(mSessionId, mSubSessionId, 184 mConfigurationParams, mSecureRangingInfo); 185 } 186 } 187 } 188