154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu/*
254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Copyright (C) 2016 The Android Open Source Project
354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu *
454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Licensed under the Apache License, Version 2.0 (the "License");
554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * you may not use this file except in compliance with the License.
654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * You may obtain a copy of the License at
754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu *
854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu *      http://www.apache.org/licenses/LICENSE-2.0
954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu *
1054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Unless required by applicable law or agreed to in writing, software
1154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * distributed under the License is distributed on an "AS IS" BASIS,
1254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * See the License for the specific language governing permissions and
1454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * limitations under the License.
1554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */
1654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
178ca4ac971a9b862fbd69c57af3a3c0029a6b9f4dPeter Qiupackage com.android.server.wifi.hotspot2.anqp;
1871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
1954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport android.util.Log;
2054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
2154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport com.android.internal.annotations.VisibleForTesting;
2254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
237ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvistimport java.net.ProtocolException;
2454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport java.nio.BufferUnderflowException;
2571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.nio.ByteBuffer;
2671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.ArrayList;
2754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiuimport java.util.Collections;
2871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.List;
2971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
3054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu/**
3154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * The IEI (Information Element Identity) contained in the Generic Container for the
3254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * 3GPP Cellular Network ANQP element.
3354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu *
3454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * Refer to Annex A of 3GPP TS 24.234 version 11.3.0 for information on the data format:
3554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu * (http://www.etsi.org/deliver/etsi_ts/124200_124299/124234/11.03.00_60/ts_124234v110300p.pdf)
3654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu */
3754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiupublic class CellularNetwork {
3854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    private static final String TAG = "CellularNetwork";
3971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
4054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    /**
4154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * IEI type for PLMN (Public Land Mobile Network) list.
4254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     */
4354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    @VisibleForTesting
4454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public static final int IEI_TYPE_PLMN_LIST = 0;
4571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
4654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    @VisibleForTesting
4754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public static final int IEI_CONTENT_LENGTH_MASK = 0x7F;
4871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
4954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    /**
5054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * Number of bytes for each PLMN (Public Land Mobile Network).
5154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     */
5254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    @VisibleForTesting
5354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public static final int PLMN_DATA_BYTES = 3;
5471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
5554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    /**
5654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * The value for comparing the third digit of MNC data with to determine if the MNC is
5754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * two or three digits.
5854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     */
5954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    private static final int MNC_2DIGIT_VALUE = 0xF;
6054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
6154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    /**
6254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * List of PLMN (Public Land Mobile Network) information.
6354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     */
6454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    private final List<String> mPlmnList;
6554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
6654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    @VisibleForTesting
6754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public CellularNetwork(List<String> plmnList) {
6854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        mPlmnList = plmnList;
6954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    }
7054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
7154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    /**
7254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * Parse a CellularNetwork from the given buffer.
7354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     *
7454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * @param payload The byte buffer to read from
7554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * @return {@link CellularNetwork}
7654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * @throws ProtocolException
7754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * @throws BufferUnderflowException
7854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     */
7954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public static CellularNetwork parse(ByteBuffer payload) throws ProtocolException {
8054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        int ieiType = payload.get() & 0xFF;
8154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        int ieiSize = payload.get() & IEI_CONTENT_LENGTH_MASK;
8271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
8354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // Skip this IEI if it is an unsupported type.
8454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        if (ieiType != IEI_TYPE_PLMN_LIST) {
8554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            Log.e(TAG, "Ignore unsupported IEI Type: " + ieiType);
8654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            // Advance the buffer position to the next IEI.
8754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            payload.position(payload.position() + ieiSize);
8854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            return null;
8954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        }
9071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
9154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // Get PLMN count.
9254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        int plmnCount = payload.get() & 0xFF;
9371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
9454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // Verify IEI size with PLMN count.  The IEI size contained the PLMN count field plus
9554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // the bytes for the PLMNs.
9654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        if (ieiSize != (plmnCount * PLMN_DATA_BYTES + 1)) {
9754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            throw new ProtocolException("IEI size and PLMN count mismatched: IEI Size=" + ieiSize
9854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu                    + " PLMN Count=" + plmnCount);
9954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        }
10071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
10154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // Process each PLMN.
10254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        List<String> plmnList = new ArrayList<>();
10354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        while (plmnCount > 0) {
10454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            plmnList.add(parsePlmn(payload));
1057ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist            plmnCount--;
10671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist        }
10754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        return new CellularNetwork(plmnList);
10871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist    }
10971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
11054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public List<String> getPlmns() {
11154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        return Collections.unmodifiableList(mPlmnList);
11254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    }
11371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
11454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    @Override
11554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public boolean equals(Object thatObject) {
11654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        if (this == thatObject) {
11754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            return true;
11871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist        }
11954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        if (!(thatObject instanceof CellularNetwork)) {
12054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu            return false;
12154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        }
12254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        CellularNetwork that = (CellularNetwork) thatObject;
12354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        return mPlmnList.equals(that.mPlmnList);
12471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist    }
12571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
12607f11f6f2ee7ec17cb08180035dfb5002aaaf5dfJan Nordqvist    @Override
12754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    public int hashCode() {
12854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        return mPlmnList.hashCode();
12971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist    }
13071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist
13171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist    @Override
13271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist    public String toString() {
13354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        return "CellularNetwork{mPlmnList=" + mPlmnList + "}";
13454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    }
13554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
13654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    /**
13754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * Parse the PLMN information from the given buffer.  A string representing a hex value
13854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * of |MCC|MNC| will be returned.
13954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     *
14054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * PLMN Coding Format:
14154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * b7                         b0
14254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * | MCC Digit 2 | MCC Digit 1 |
14354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * | MNC Digit 3 | MCC Digit 3 |
14454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * | MNC Digit 2 | MNC Digit 1 |
14554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     *
14654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * @param payload The buffer to read from.
14754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * @return {@Link String}
14854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     * @throws BufferUnderflowException
14954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu     */
15054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu    private static String parsePlmn(ByteBuffer payload) {
15154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        byte[] plmn = new byte[PLMN_DATA_BYTES];
15254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        payload.get(plmn);
15354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
15454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // Formatted as | MCC Digit 1 | MCC Digit 2 | MCC Digit 3 |
15554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        int mcc = ((plmn[0] << 8) & 0xF00) | (plmn[0] & 0x0F0) | (plmn[1] & 0x00F);
15654481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
15754481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // Formated as |MNC Digit 1 | MNC Digit 2 |
15854481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        int mnc = ((plmn[2] << 4) & 0xF0) | ((plmn[2] >> 4) & 0x0F);
15954481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu
16054481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // The digit 3 of MNC decides if the MNC is 2 or 3 digits number.  When it is equal to
16154481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        // 0xF, MNC is a 2 digit value. Otherwise, it is a 3 digit number.
16254481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        int mncDigit3 = (plmn[1] >> 4) & 0x0F;
16354481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu        return (mncDigit3 != MNC_2DIGIT_VALUE)
16454481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu                ? String.format("%03x%03x", mcc, (mnc << 4) | mncDigit3)
16554481f724e41249c4e036a9f59e8cb3e6fb821d8Peter Qiu                : String.format("%03x%02x", mcc, mnc);
16671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist    }
16771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist}
168