1package com.android.anqp;
2
3import java.net.ProtocolException;
4import java.nio.ByteBuffer;
5import java.nio.ByteOrder;
6import java.nio.charset.StandardCharsets;
7import java.util.ArrayList;
8import java.util.List;
9
10import static com.android.anqp.Constants.BYTE_MASK;
11import static com.android.anqp.Constants.SHORT_MASK;
12
13/**
14 * An OSU Provider, as specified in
15 * Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00,
16 * section 4.8.1
17 */
18public class OSUProvider {
19
20    public enum OSUMethod {OmaDm, SoapXml}
21
22    private final String mSSID;
23    private final List<I18Name> mNames;
24    private final String mOSUServer;
25    private final List<OSUMethod> mOSUMethods;
26    private final List<IconInfo> mIcons;
27    private final String mOsuNai;
28    private final List<I18Name> mServiceDescriptions;
29    private final int mHashCode;
30
31    public OSUProvider(String ssid, ByteBuffer payload) throws ProtocolException {
32        if (payload.remaining() < 11) {
33            throw new ProtocolException("Truncated OSU provider: " + payload.remaining());
34        }
35
36        mSSID = ssid;
37
38        int length = payload.getShort() & SHORT_MASK;
39        int namesLength = payload.getShort() & SHORT_MASK;
40
41        ByteBuffer namesBuffer = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
42        namesBuffer.limit(namesBuffer.position() + namesLength);
43        payload.position(payload.position() + namesLength);
44
45        mNames = new ArrayList<>();
46
47        while (namesBuffer.hasRemaining()) {
48            mNames.add(new I18Name(namesBuffer));
49        }
50
51        mOSUServer = Constants.getPrefixedString(payload, 1, StandardCharsets.UTF_8);
52        int methodLength = payload.get() & BYTE_MASK;
53        mOSUMethods = new ArrayList<>(methodLength);
54        while (methodLength > 0) {
55            int methodID = payload.get() & BYTE_MASK;
56            mOSUMethods.add(methodID < OSUMethod.values().length ?
57                    OSUMethod.values()[methodID] :
58                    null);
59            methodLength--;
60        }
61
62        int iconsLength = payload.getShort() & SHORT_MASK;
63        ByteBuffer iconsBuffer = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
64        iconsBuffer.limit(iconsBuffer.position() + iconsLength);
65        payload.position(payload.position() + iconsLength);
66
67        mIcons = new ArrayList<>();
68
69        while (iconsBuffer.hasRemaining()) {
70            mIcons.add(new IconInfo(iconsBuffer));
71        }
72
73        mOsuNai = Constants.getPrefixedString(payload, 1, StandardCharsets.UTF_8, true);
74
75        int descriptionsLength = payload.getShort() & SHORT_MASK;
76        ByteBuffer descriptionsBuffer = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
77        descriptionsBuffer.limit(descriptionsBuffer.position() + descriptionsLength);
78        payload.position(payload.position() + descriptionsLength);
79
80        mServiceDescriptions = new ArrayList<>();
81
82        while (descriptionsBuffer.hasRemaining()) {
83            mServiceDescriptions.add(new I18Name(descriptionsBuffer));
84        }
85
86        int result = mNames.hashCode();
87        result = 31 * result + mSSID.hashCode();
88        result = 31 * result + mOSUServer.hashCode();
89        result = 31 * result + mOSUMethods.hashCode();
90        result = 31 * result + mIcons.hashCode();
91        result = 31 * result + (mOsuNai != null ? mOsuNai.hashCode() : 0);
92        result = 31 * result + mServiceDescriptions.hashCode();
93        mHashCode = result;
94    }
95
96    public String getSSID() {
97        return mSSID;
98    }
99
100    public List<I18Name> getNames() {
101        return mNames;
102    }
103
104    public String getOSUServer() {
105        return mOSUServer;
106    }
107
108    public List<OSUMethod> getOSUMethods() {
109        return mOSUMethods;
110    }
111
112    public List<IconInfo> getIcons() {
113        return mIcons;
114    }
115
116    public String getOsuNai() {
117        return mOsuNai;
118    }
119
120    public List<I18Name> getServiceDescriptions() {
121        return mServiceDescriptions;
122    }
123
124    @Override
125    public boolean equals(Object o) {
126        if (this == o) return true;
127        if (o == null || getClass() != o.getClass()) return false;
128
129        OSUProvider that = (OSUProvider) o;
130
131        if (!mSSID.equals(that.mSSID)) return false;
132        if (!mOSUServer.equals(that.mOSUServer)) return false;
133        if (!mNames.equals(that.mNames)) return false;
134        if (!mServiceDescriptions.equals(that.mServiceDescriptions)) return false;
135        if (!mIcons.equals(that.mIcons)) return false;
136        if (!mOSUMethods.equals(that.mOSUMethods)) return false;
137        if (mOsuNai != null ? !mOsuNai.equals(that.mOsuNai) : that.mOsuNai != null) return false;
138
139        return true;
140    }
141
142    @Override
143    public int hashCode() {
144        return mHashCode;
145    }
146
147    @Override
148    public String toString() {
149        return "OSUProvider{" +
150                "names=" + mNames +
151                ", OSUServer='" + mOSUServer + '\'' +
152                ", OSUMethods=" + mOSUMethods +
153                ", icons=" + mIcons +
154                ", NAI='" + mOsuNai + '\'' +
155                ", serviceDescriptions=" + mServiceDescriptions +
156                '}';
157    }
158}
159