1 /* 2 * Copyright (C) 2020 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.internal.net.eap.message.ttls; 18 19 import com.android.internal.annotations.VisibleForTesting; 20 21 import java.nio.ByteBuffer; 22 23 /** The outbound fragmentation helper is responsible for fragmenting outbound EAP-TTLS data */ 24 public class EapTtlsOutboundFragmentationHelper { 25 private static final String TAG = EapTtlsInboundFragmentationHelper.class.getSimpleName(); 26 27 private static final int DEFAULT_FRAGMENTATION_SIZE = 1024; 28 29 // Defines the outbound fragment size 30 private final int mFragmentSize; 31 private ByteBuffer mFragmentedData; 32 33 // TODO(b/165668196): Modify outbound fragmentation helper to be per-message in EAP-TTLS EapTtlsOutboundFragmentationHelper()34 public EapTtlsOutboundFragmentationHelper() { 35 this(DEFAULT_FRAGMENTATION_SIZE); 36 } 37 38 /** 39 * Sets a specific fragment size for the fragmentation helper instance. This should only be used 40 * for testing. 41 * 42 * @param fragmentSize the fragment size to set 43 */ 44 @VisibleForTesting EapTtlsOutboundFragmentationHelper(int fragmentSize)45 public EapTtlsOutboundFragmentationHelper(int fragmentSize) { 46 mFragmentSize = fragmentSize; 47 } 48 49 /** 50 * Prepares an outbound message for fragmentation 51 * 52 * @param data the data to fragment 53 */ setupOutboundFragmentation(byte[] data)54 public void setupOutboundFragmentation(byte[] data) { 55 mFragmentedData = ByteBuffer.wrap(data); 56 } 57 58 /** 59 * Returns fragmented data ready to be sent to the server 60 * 61 * @return a fragmentation result which contains the fragmented data as well as a boolean 62 * indicating whether more fragments will follow 63 * @throws IllegalStateException if this is called when a fragmentation session is not in 64 * progress 65 */ getNextOutboundFragment()66 public FragmentationResult getNextOutboundFragment() throws IllegalStateException { 67 if (mFragmentedData == null || !mFragmentedData.hasRemaining()) { 68 throw new IllegalStateException( 69 "Error producing next outbound fragment. No fragmented packets are currently" 70 + " being processed."); 71 } 72 // If the data in the buffer is larger than the fragmentSize, produce a fragment of 73 // fragmentSize. Otherwise, return all the remaining data 74 int outboundDataSize = Math.min(mFragmentSize, mFragmentedData.remaining()); 75 byte[] outboundData = new byte[outboundDataSize]; 76 mFragmentedData.get(outboundData); 77 78 return new FragmentationResult(outboundData, mFragmentedData.hasRemaining()); 79 } 80 81 /** 82 * Indicates whether there is additional outbound fragmented data to be sent 83 * 84 * <p>This should be called in case the server does not send an ack but sends a regular request 85 * in response to a fragment. This will allow the state machine to detect an unexpected request 86 * error. 87 * 88 * @return a boolean indicating whether there are outbound fragments that need to be sent 89 */ hasRemainingFragments()90 public boolean hasRemainingFragments() { 91 return mFragmentedData != null && mFragmentedData.hasRemaining(); 92 } 93 94 /** FragmentationResult encapsulates the results of outbound fragmentation processing */ 95 public class FragmentationResult { 96 97 public final boolean hasRemainingFragments; 98 public final byte[] fragmentedData; 99 FragmentationResult(byte[] fragmentedData, boolean hasRemainingFragments)100 public FragmentationResult(byte[] fragmentedData, boolean hasRemainingFragments) { 101 this.fragmentedData = fragmentedData; 102 this.hasRemainingFragments = hasRemainingFragments; 103 } 104 } 105 } 106