1package com.android.server.wifi.hotspot2.anqp;
2
3import com.android.internal.annotations.VisibleForTesting;
4
5import java.net.ProtocolException;
6import java.nio.ByteBuffer;
7import java.util.HashSet;
8import java.util.Set;
9
10/**
11 * The IP Address Type availability ANQP Element, IEEE802.11-2012 section 8.4.4.9
12 *
13 * Format:
14 *
15 * | IP Address |
16 *       1
17 * b0                           b7
18 * | IPv6 Address | IPv4 Address |
19 *     2 bits          6 bits
20 *
21 * IPv4 Address field values:
22 * 0 - Address type not available
23 * 1 - Public IPv4 address available
24 * 2 - Port-restricted IPv4 address available
25 * 3 - Single NATed private IPv4 address available
26 * 4 - Single NATed private IPv4 address available
27 * 5 - Port-restricted IPv4 address and single NATed IPv4 address available
28 * 6 - Port-restricted IPv4 address and double NATed IPv4 address available
29 * 7 - Availability of the address type is not known
30 *
31 * IPv6 Address field values:
32 * 0 - Address type not available
33 * 1 - Address type not available
34 * 2 - Availability of the address type not known
35 *
36 */
37public class IPAddressTypeAvailabilityElement extends ANQPElement {
38    @VisibleForTesting
39    public static final int EXPECTED_BUFFER_LENGTH = 1;
40
41    /**
42     * Constants for IPv4 availability.
43     */
44    public static final int IPV4_NOT_AVAILABLE = 0;
45    public static final int IPV4_PUBLIC = 1;
46    public static final int IPV4_PORT_RESTRICTED = 2;
47    public static final int IPV4_SINGLE_NAT = 3;
48    public static final int IPV4_DOUBLE_NAT = 4;
49    public static final int IPV4_PORT_RESTRICTED_AND_SINGLE_NAT = 5;
50    public static final int IPV4_PORT_RESTRICTED_AND_DOUBLE_NAT = 6;
51    public static final int IPV4_UNKNOWN = 7;
52    private static final Set<Integer> IPV4_AVAILABILITY = new HashSet<Integer>();
53    static {
54        IPV4_AVAILABILITY.add(IPV4_NOT_AVAILABLE);
55        IPV4_AVAILABILITY.add(IPV4_PUBLIC);
56        IPV4_AVAILABILITY.add(IPV4_PORT_RESTRICTED);
57        IPV4_AVAILABILITY.add(IPV4_SINGLE_NAT);
58        IPV4_AVAILABILITY.add(IPV4_DOUBLE_NAT);
59        IPV4_AVAILABILITY.add(IPV4_PORT_RESTRICTED_AND_SINGLE_NAT);
60        IPV4_AVAILABILITY.add(IPV4_PORT_RESTRICTED_AND_DOUBLE_NAT);
61    }
62
63    /**
64     * Constants for IPv6 availability.
65     */
66    public static final int IPV6_NOT_AVAILABLE = 0;
67    public static final int IPV6_AVAILABLE = 1;
68    public static final int IPV6_UNKNOWN = 2;
69    private static final Set<Integer> IPV6_AVAILABILITY = new HashSet<Integer>();
70    static {
71        IPV6_AVAILABILITY.add(IPV6_NOT_AVAILABLE);
72        IPV6_AVAILABILITY.add(IPV6_AVAILABLE);
73        IPV6_AVAILABILITY.add(IPV6_UNKNOWN);
74    }
75
76    private static final int IPV4_AVAILABILITY_MASK = 0x3F;
77    private static final int IPV6_AVAILABILITY_MASK = 0x3;
78
79    private final int mV4Availability;
80    private final int mV6Availability;
81
82    @VisibleForTesting
83    public IPAddressTypeAvailabilityElement(int v4Availability, int v6Availability) {
84        super(Constants.ANQPElementType.ANQPIPAddrAvailability);
85        mV4Availability = v4Availability;
86        mV6Availability = v6Availability;
87    }
88
89    /**
90     * Parse an IPAddressTypeAvailabilityElement from the given buffer.
91     *
92     * @param payload The byte buffer to read from
93     * @return {@link IPAddressTypeAvailabilityElement}
94     * @throws ProtocolException
95     */
96    public static IPAddressTypeAvailabilityElement parse(ByteBuffer payload)
97            throws ProtocolException {
98        if (payload.remaining() != EXPECTED_BUFFER_LENGTH) {
99            throw new ProtocolException("Unexpected buffer length: " + payload.remaining());
100        }
101
102        int ipField = payload.get() & 0xFF;
103
104        int v6Availability = ipField & IPV6_AVAILABILITY_MASK;
105        if (!IPV6_AVAILABILITY.contains(v6Availability)) {
106            v6Availability = IPV6_UNKNOWN;
107        }
108
109        int v4Availability = (ipField >> 2) & IPV4_AVAILABILITY_MASK;
110        if (!IPV4_AVAILABILITY.contains(v4Availability)) {
111            v4Availability = IPV4_UNKNOWN;
112        }
113
114        return new IPAddressTypeAvailabilityElement(v4Availability, v6Availability);
115    }
116
117    public int getV4Availability() {
118        return mV4Availability;
119    }
120
121    public int getV6Availability() {
122        return mV6Availability;
123    }
124
125    @Override
126    public boolean equals(Object thatObject) {
127        if (this == thatObject) {
128            return true;
129        }
130        if (!(thatObject instanceof IPAddressTypeAvailabilityElement)) {
131            return false;
132        }
133        IPAddressTypeAvailabilityElement that = (IPAddressTypeAvailabilityElement) thatObject;
134        return mV4Availability == that.mV4Availability && mV6Availability == that.mV6Availability;
135    }
136
137    @Override
138    public int hashCode() {
139        return mV4Availability << 2 + mV6Availability;
140    }
141
142    @Override
143    public String toString() {
144        return "IPAddressTypeAvailability{" +
145                "mV4Availability=" + mV4Availability +
146                ", mV6Availability=" + mV6Availability +
147                '}';
148    }
149}
150