1 /* 2 * Copyright (C) 2016 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.wifi.hotspot2.anqp; 18 19 import com.android.internal.annotations.VisibleForTesting; 20 import com.android.server.wifi.ByteBufferReader; 21 22 import java.net.ProtocolException; 23 import java.nio.ByteBuffer; 24 import java.nio.ByteOrder; 25 26 /** 27 * The WAN Metrics vendor specific ANQP Element, 28 * Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00, 29 * section 4.4 30 * 31 * Format: 32 * | WAN Info | Downlink Speed | Uplink Speed | Downlink Load | Uplink Load | LMD | 33 * 1 4 4 1 1 2 34 * 35 * WAN Info Format: 36 * | Link Status | Symmetric Link | At Capacity | Reserved | 37 * B0 B1 B2 B3 B4 - B7 38 */ 39 public class HSWanMetricsElement extends ANQPElement { 40 public static final int LINK_STATUS_RESERVED = 0; 41 public static final int LINK_STATUS_UP = 1; 42 public static final int LINK_STATUS_DOWN = 2; 43 public static final int LINK_STATUS_TEST = 3; 44 45 @VisibleForTesting 46 public static final int EXPECTED_BUFFER_SIZE = 13; 47 48 @VisibleForTesting 49 public static final int LINK_STATUS_MASK = (1 << 0 | 1 << 1); 50 51 @VisibleForTesting 52 public static final int SYMMETRIC_LINK_MASK = 1 << 2; 53 54 @VisibleForTesting 55 public static final int AT_CAPACITY_MASK = 1 << 3; 56 57 private static final int MAX_LOAD = 256; 58 59 private final int mStatus; 60 private final boolean mSymmetric; 61 private final boolean mAtCapacity; 62 private final long mDownlinkSpeed; 63 private final long mUplinkSpeed; 64 private final int mDownlinkLoad; 65 private final int mUplinkLoad; 66 private final int mLMD; // Load Measurement Duration. 67 68 @VisibleForTesting HSWanMetricsElement(int status, boolean symmetric, boolean atCapacity, long downlinkSpeed, long uplinkSpeed, int downlinkLoad, int uplinkLoad, int lmd)69 public HSWanMetricsElement(int status, boolean symmetric, boolean atCapacity, 70 long downlinkSpeed, long uplinkSpeed, int downlinkLoad, int uplinkLoad, int lmd) { 71 super(Constants.ANQPElementType.HSWANMetrics); 72 mStatus = status; 73 mSymmetric = symmetric; 74 mAtCapacity = atCapacity; 75 mDownlinkSpeed = downlinkSpeed; 76 mUplinkSpeed = uplinkSpeed; 77 mDownlinkLoad = downlinkLoad; 78 mUplinkLoad = uplinkLoad; 79 mLMD = lmd; 80 } 81 82 /** 83 * Parse a HSWanMetricsElement from the given buffer. 84 * 85 * @param payload The byte buffer to read from 86 * @return {@link HSWanMetricsElement} 87 * @throws ProtocolException 88 */ parse(ByteBuffer payload)89 public static HSWanMetricsElement parse(ByteBuffer payload) 90 throws ProtocolException { 91 if (payload.remaining() != EXPECTED_BUFFER_SIZE) { 92 throw new ProtocolException("Unexpected buffer size: " + payload.remaining()); 93 } 94 95 int wanInfo = payload.get() & 0xFF; 96 int status = wanInfo & LINK_STATUS_MASK; 97 boolean symmetric = (wanInfo & SYMMETRIC_LINK_MASK) != 0; 98 boolean capped = (wanInfo & AT_CAPACITY_MASK) != 0; 99 long downlinkSpeed = ByteBufferReader.readInteger(payload, ByteOrder.LITTLE_ENDIAN, 4) 100 & 0xFFFFFFFFL; 101 long uplinkSpeed = ByteBufferReader.readInteger(payload, ByteOrder.LITTLE_ENDIAN, 4) 102 & 0xFFFFFFFFL; 103 int downlinkLoad = payload.get() & 0xFF; 104 int uplinkLoad = payload.get() & 0xFF; 105 int lmd = (int) ByteBufferReader.readInteger(payload, ByteOrder.LITTLE_ENDIAN, 2) & 0xFFFF; 106 return new HSWanMetricsElement(status, symmetric, capped, downlinkSpeed, uplinkSpeed, 107 downlinkLoad, uplinkLoad, lmd); 108 } 109 getStatus()110 public int getStatus() { 111 return mStatus; 112 } 113 isSymmetric()114 public boolean isSymmetric() { 115 return mSymmetric; 116 } 117 isAtCapacity()118 public boolean isAtCapacity() { 119 return mAtCapacity; 120 } 121 getDownlinkSpeed()122 public long getDownlinkSpeed() { 123 return mDownlinkSpeed; 124 } 125 getUplinkSpeed()126 public long getUplinkSpeed() { 127 return mUplinkSpeed; 128 } 129 getDownlinkLoad()130 public int getDownlinkLoad() { 131 return mDownlinkLoad; 132 } 133 getUplinkLoad()134 public int getUplinkLoad() { 135 return mUplinkLoad; 136 } 137 getLMD()138 public int getLMD() { 139 return mLMD; 140 } 141 142 /** 143 * Check if the WAN Metrics ANQP-element contains values other than all 0's 144 * 145 * @return true if element contains non-0 values, false otherwise 146 */ isElementInitialized()147 public boolean isElementInitialized() { 148 // Check if the WAN Metrics ANQP element is initialized with values other than 0's 149 if (mStatus == LINK_STATUS_RESERVED && !mAtCapacity && !mSymmetric && mDownlinkLoad == 0 150 && mDownlinkSpeed == 0 && mUplinkLoad == 0 && mUplinkSpeed == 0 && mLMD == 0) { 151 // WAN Metrics ANQP element is not initialized in this network. Ignore it. 152 return false; 153 } 154 return true; 155 } 156 157 @Override equals(Object thatObject)158 public boolean equals(Object thatObject) { 159 if (this == thatObject) { 160 return true; 161 } 162 if (!(thatObject instanceof HSWanMetricsElement)) { 163 return false; 164 } 165 HSWanMetricsElement that = (HSWanMetricsElement) thatObject; 166 return mStatus == that.mStatus 167 && mSymmetric == that.mSymmetric 168 && mAtCapacity == that.mAtCapacity 169 && mDownlinkSpeed == that.mDownlinkSpeed 170 && mUplinkSpeed == that.mUplinkSpeed 171 && mDownlinkLoad == that.mDownlinkLoad 172 && mUplinkLoad == that.mUplinkLoad 173 && mLMD == that.mLMD; 174 } 175 176 @Override hashCode()177 public int hashCode() { 178 return (int) (mStatus + mDownlinkSpeed + mUplinkSpeed + mDownlinkLoad 179 + mUplinkLoad + mLMD); 180 } 181 182 @Override toString()183 public String toString() { 184 return String.format("HSWanMetrics{mStatus=%s, mSymmetric=%s, mAtCapacity=%s, " 185 + "mDlSpeed=%d, mUlSpeed=%d, mDlLoad=%f, mUlLoad=%f, mLMD=%d}", 186 mStatus, mSymmetric, mAtCapacity, 187 mDownlinkSpeed, mUplinkSpeed, 188 mDownlinkLoad * 100.0 / MAX_LOAD, 189 mUplinkLoad * 100.0 / MAX_LOAD, 190 mLMD); 191 } 192 } 193