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 mCapped; 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 69 public HSWanMetricsElement(int status, boolean symmetric, boolean capped, long downlinkSpeed, 70 long uplinkSpeed, int downlinkLoad, int uplinkLoad, int lmd) { 71 super(Constants.ANQPElementType.HSWANMetrics); 72 mStatus = status; 73 mSymmetric = symmetric; 74 mCapped = capped; 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 */ 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 110 public int getStatus() { 111 return mStatus; 112 } 113 114 public boolean isSymmetric() { 115 return mSymmetric; 116 } 117 118 public boolean isCapped() { 119 return mCapped; 120 } 121 122 public long getDownlinkSpeed() { 123 return mDownlinkSpeed; 124 } 125 126 public long getUplinkSpeed() { 127 return mUplinkSpeed; 128 } 129 130 public int getDownlinkLoad() { 131 return mDownlinkLoad; 132 } 133 134 public int getUplinkLoad() { 135 return mUplinkLoad; 136 } 137 138 public int getLMD() { 139 return mLMD; 140 } 141 142 @Override 143 public boolean equals(Object thatObject) { 144 if (this == thatObject) { 145 return true; 146 } 147 if (!(thatObject instanceof HSWanMetricsElement)) { 148 return false; 149 } 150 HSWanMetricsElement that = (HSWanMetricsElement) thatObject; 151 return mStatus == that.mStatus 152 && mSymmetric == that.mSymmetric 153 && mCapped == that.mCapped 154 && mDownlinkSpeed == that.mDownlinkSpeed 155 && mUplinkSpeed == that.mUplinkSpeed 156 && mDownlinkLoad == that.mDownlinkLoad 157 && mUplinkLoad == that.mUplinkLoad 158 && mLMD == that.mLMD; 159 } 160 161 @Override 162 public int hashCode() { 163 return (int) (mStatus + mDownlinkSpeed + mUplinkSpeed + mDownlinkLoad 164 + mUplinkLoad + mLMD); 165 } 166 167 @Override 168 public String toString() { 169 return String.format("HSWanMetrics{mStatus=%s, mSymmetric=%s, mCapped=%s, " + 170 "mDlSpeed=%d, mUlSpeed=%d, mDlLoad=%f, mUlLoad=%f, mLMD=%d}", 171 mStatus, mSymmetric, mCapped, 172 mDownlinkSpeed, mUplinkSpeed, 173 mDownlinkLoad * 100.0 / MAX_LOAD, 174 mUplinkLoad * 100.0 / MAX_LOAD, 175 mLMD); 176 } 177 } 178