1 /* 2 * Copyright (C) 2024 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 android.net.wifi.usd; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.SystemApi; 25 import android.net.wifi.aware.TlvBufferUtils; 26 import android.net.wifi.flags.Flags; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.util.Arrays; 31 import java.util.List; 32 import java.util.Objects; 33 34 /** 35 * USD configuration for publish and subscribe operation. This is the base class and not intended 36 * to be created directly. 37 * 38 * @hide 39 */ 40 @SystemApi 41 @FlaggedApi(Flags.FLAG_USD) 42 public abstract class Config { 43 /** @hide */ 44 public static final int MAX_NUM_OF_OPERATING_FREQUENCIES = 32; 45 46 /** 47 * Transmission type. 48 * 49 * @hide 50 */ 51 @IntDef({TRANSMISSION_TYPE_UNICAST, TRANSMISSION_TYPE_MULTICAST}) 52 @Retention(RetentionPolicy.SOURCE) 53 public @interface TransmissionType { 54 } 55 56 /** 57 * A unicast transmission sends data from one device to a single, specific destination device. 58 */ 59 public static final int TRANSMISSION_TYPE_UNICAST = 0; 60 61 /** 62 * A multicast transmission sends data from one device to a group of devices on the network 63 * simultaneously. 64 */ 65 public static final int TRANSMISSION_TYPE_MULTICAST = 1; 66 67 /** 68 * Subscribe type. 69 * 70 * @hide 71 */ 72 @IntDef({SUBSCRIBE_TYPE_PASSIVE, SUBSCRIBE_TYPE_ACTIVE}) 73 @Retention(RetentionPolicy.SOURCE) 74 public @interface SubscribeType { 75 } 76 77 /** 78 * Defines a passive subscribe session - a subscribe session where subscribe packets are not 79 * transmitted over-the-air and the device listens and matches to received publish packets. 80 */ 81 public static final int SUBSCRIBE_TYPE_PASSIVE = 0; 82 83 /** 84 * Defines an active subscribe session - a subscribe session where subscribe packets are 85 * transmitted over-the-air. 86 */ 87 public static final int SUBSCRIBE_TYPE_ACTIVE = 1; 88 89 /** 90 * Service Protocol Type. 91 * 92 * @hide 93 */ 94 @IntDef({SERVICE_PROTO_TYPE_GENERIC, SERVICE_PROTO_TYPE_CSA_MATTER}) 95 @Retention(RetentionPolicy.SOURCE) 96 public @interface ServiceProtoType { 97 } 98 99 /** 100 * Generic type. 101 */ 102 public static final int SERVICE_PROTO_TYPE_GENERIC = 0; 103 104 /** 105 * CSA (Connectivity Standards Alliance) Matter. 106 * Note: CSA Matter is an open-source standard for smart home technology that allows devices to 107 * work with any Matter-certified ecosystem. 108 */ 109 public static final int SERVICE_PROTO_TYPE_CSA_MATTER = 1; 110 111 private final byte[] mServiceName; 112 private final int mTtlSeconds; 113 @ServiceProtoType 114 private final int mServiceProtoType; 115 private final byte[] mTxMatchFilterTlv; 116 private final byte[] mRxMatchFilterTlv; 117 private final byte[] mServiceSpecificInfo; 118 private final int[] mOperatingFrequencies; 119 120 /** 121 * @hide 122 */ Config(@onNull byte[] serviceName, int ttlSeconds, int serviceProtoType, @Nullable byte[] txMatchFilterTlv, @Nullable byte[] rxMatchFilterTlv, @Nullable byte[] serviceSpecificInfo, @Nullable int[] operatingFrequencies)123 public Config(@NonNull byte[] serviceName, int ttlSeconds, int serviceProtoType, 124 @Nullable byte[] txMatchFilterTlv, @Nullable byte[] rxMatchFilterTlv, 125 @Nullable byte[] serviceSpecificInfo, @Nullable int[] operatingFrequencies) { 126 mServiceName = serviceName; 127 mTtlSeconds = ttlSeconds; 128 mServiceProtoType = serviceProtoType; 129 mTxMatchFilterTlv = txMatchFilterTlv; 130 mRxMatchFilterTlv = rxMatchFilterTlv; 131 mServiceSpecificInfo = serviceSpecificInfo; 132 mOperatingFrequencies = operatingFrequencies; 133 } 134 135 /** 136 * Gets the service name of the USD session. 137 * <p> 138 * The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length. 139 * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric 140 * values (A-Z, a-z, 0-9), the hyphen ('-'), the period ('.') and the underscore ('_'). All 141 * valid multi-byte UTF-8 characters are acceptable in a Service Name. 142 * 143 * @return service name 144 */ 145 @NonNull getServiceName()146 public byte[] getServiceName() { 147 return mServiceName; 148 } 149 150 /** 151 * Gets the time interval (in seconds) a USD session will be alive. When the TTL is reached the 152 * session will be terminated with an event. 153 * 154 * @return ttl value in seconds 155 */ 156 @IntRange(from = 0) getTtlSeconds()157 public int getTtlSeconds() { 158 return mTtlSeconds; 159 } 160 161 /** 162 * Get the Service protocol type for the USD session. 163 * 164 * @return service protocol type as defined in {@code SERVICE_PROTOCOL_TYPE_*} 165 */ 166 @ServiceProtoType getServiceProtoType()167 public int getServiceProtoType() { 168 return mServiceProtoType; 169 } 170 171 /** 172 * Gets the Tx filter which is an ordered sequence of (length, value) pairs to be included in 173 * the USD discovery frame. 174 * 175 * @return tx match filter or empty list 176 */ 177 @NonNull getTxMatchFilter()178 public List<byte[]> getTxMatchFilter() { 179 return new TlvBufferUtils.TlvIterable(0, 1, mTxMatchFilterTlv).toList(); 180 } 181 182 /** 183 * @return tx match filter in TLV format 184 * @hide 185 */ 186 @Nullable getTxMatchFilterTlv()187 public byte[] getTxMatchFilterTlv() { 188 return mTxMatchFilterTlv; 189 } 190 191 /** 192 * Gets the Rx match filter, which is an ordered sequence of (length, value) pairs that specify 193 * further the response conditions beyond the service name used to filter subscribe messages. 194 * 195 * @return rx match filter or empty list 196 */ 197 @NonNull getRxMatchFilter()198 public List<byte[]> getRxMatchFilter() { 199 return new TlvBufferUtils.TlvIterable(0, 1, mRxMatchFilterTlv).toList(); 200 } 201 202 /** 203 * @return receive match filter in TLV format. 204 * @hide 205 */ 206 @Nullable getRxMatchFilterTlv()207 public byte[] getRxMatchFilterTlv() { 208 return mRxMatchFilterTlv; 209 } 210 211 /** 212 * Get the service specific information set for the USD session. 213 * 214 * @return byte array or null 215 */ 216 @Nullable getServiceSpecificInfo()217 public byte[] getServiceSpecificInfo() { 218 return mServiceSpecificInfo; 219 } 220 221 /** 222 * Get the frequencies where the USD session operates if overridden by {@code 223 * setOperatingFrequenciesMhz(int[])}. If null, the application has not set the operating 224 * frequencies using {@link PublishConfig.Builder#setOperatingFrequenciesMhz(int[])} for the 225 * publisher or {@link SubscribeConfig.Builder#setOperatingFrequenciesMhz(int[])} for the 226 * subscriber. 227 * 228 * <p>If the operating frequencies are not set the default behavior for the publisher and 229 * subscriber is, 230 * <ul> 231 * <li>The publisher defaults to channel 6 (in the 2.4 GHz band) and a list of allowed channels 232 * in the 2.4 GHz and 5 GHz bands for multichannel publishing. Publisher may prioritize the 233 * channel with Access Points having best RSSI. 234 * <li>The subscriber defaults to either channel 6 (in the 2.4 Ghz band) or Station channel or 235 * pick a channel from 236 * {@link SubscribeConfig.Builder#setRecommendedOperatingFrequenciesMhz(int[])} in given order 237 * of preference. 238 * </ul> 239 * 240 * @return an array of frequencies or null 241 */ 242 @Nullable getOperatingFrequenciesMhz()243 public int[] getOperatingFrequenciesMhz() { 244 return mOperatingFrequencies; 245 } 246 247 @Override toString()248 public String toString() { 249 return "Config{" + "mServiceName=" + Arrays.toString(mServiceName) + ", mTtlSeconds=" 250 + mTtlSeconds + ", mServiceProtoType=" + mServiceProtoType + ", mTxMatchFilterTlv=" 251 + Arrays.toString(mTxMatchFilterTlv) + ", mRxMatchFilterTlv=" + Arrays.toString( 252 mRxMatchFilterTlv) + ", mServiceSpecificInfo=" + Arrays.toString( 253 mServiceSpecificInfo) + ", mOperatingFrequencies=" + Arrays.toString( 254 mOperatingFrequencies) + '}'; 255 } 256 257 @Override equals(Object o)258 public boolean equals(Object o) { 259 if (this == o) return true; 260 if (!(o instanceof Config config)) return false; 261 return mTtlSeconds == config.mTtlSeconds && mServiceProtoType == config.mServiceProtoType 262 && Arrays.equals(mServiceName, config.mServiceName) 263 && Arrays.equals(mTxMatchFilterTlv, config.mTxMatchFilterTlv) 264 && Arrays.equals(mRxMatchFilterTlv, config.mRxMatchFilterTlv) 265 && Arrays.equals(mServiceSpecificInfo, config.mServiceSpecificInfo) 266 && Arrays.equals(mOperatingFrequencies, config.mOperatingFrequencies); 267 } 268 269 @Override hashCode()270 public int hashCode() { 271 int result = Objects.hash(mTtlSeconds, mServiceProtoType); 272 result = 31 * result + Arrays.hashCode(mServiceName); 273 result = 31 * result + Arrays.hashCode(mTxMatchFilterTlv); 274 result = 31 * result + Arrays.hashCode(mRxMatchFilterTlv); 275 result = 31 * result + Arrays.hashCode(mServiceSpecificInfo); 276 result = 31 * result + Arrays.hashCode(mOperatingFrequencies); 277 return result; 278 } 279 } 280