1 package com.android.server.wifi.hotspot2.anqp;
2 
3 import com.android.internal.annotations.VisibleForTesting;
4 
5 import java.net.ProtocolException;
6 import java.nio.ByteBuffer;
7 import java.util.HashSet;
8 import 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  */
37 public 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
IPAddressTypeAvailabilityElement(int v4Availability, int v6Availability)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      */
parse(ByteBuffer payload)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 
getV4Availability()117     public int getV4Availability() {
118         return mV4Availability;
119     }
120 
getV6Availability()121     public int getV6Availability() {
122         return mV6Availability;
123     }
124 
125     @Override
equals(Object thatObject)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
hashCode()138     public int hashCode() {
139         return mV4Availability << 2 + mV6Availability;
140     }
141 
142     @Override
toString()143     public String toString() {
144         return "IPAddressTypeAvailability{" +
145                 "mV4Availability=" + mV4Availability +
146                 ", mV6Availability=" + mV6Availability +
147                 '}';
148     }
149 }
150