• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 android.net.wifi.p2p;
18 
19 import android.annotation.Nullable;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 
24 import java.net.Inet4Address;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31 
32 /**
33  * A class representing a Wi-Fi P2p group. A p2p group consists of a single group
34  * owner and one or more clients. In the case of a group with only two devices, one
35  * will be the group owner and the other will be a group client.
36  *
37  * {@see WifiP2pManager}
38  */
39 public class WifiP2pGroup implements Parcelable {
40 
41     /**
42      * The temporary network id.
43      * @see #getNetworkId()
44      */
45     public static final int NETWORK_ID_TEMPORARY = -1;
46 
47     /**
48      * The temporary network id.
49      *
50      * @hide
51      */
52     @UnsupportedAppUsage
53     public static final int TEMPORARY_NET_ID = NETWORK_ID_TEMPORARY;
54 
55     /**
56      * The persistent network id.
57      * If a matching persistent profile is found, use it.
58      * Otherwise, create a new persistent profile.
59      * @see #getNetworkId()
60      */
61     public static final int NETWORK_ID_PERSISTENT = -2;
62 
63     /**
64      * Group owner P2P interface MAC address.
65      * @hide
66      */
67     @UnsupportedAppUsage
68     public byte[] interfaceAddress;
69 
70     /** The network name */
71     private String mNetworkName;
72 
73     /** Group owner */
74     private WifiP2pDevice mOwner;
75 
76     /** Device is group owner */
77     private boolean mIsGroupOwner;
78 
79     /** Group clients */
80     private List<WifiP2pDevice> mClients = new ArrayList<WifiP2pDevice>();
81 
82     /** The passphrase used for WPA2-PSK */
83     private String mPassphrase;
84 
85     private String mInterface;
86 
87     /** The network ID in wpa_supplicant */
88     private int mNetId;
89 
90     /** The frequency (in MHz) used by this group */
91     private int mFrequency;
92 
93     /**
94      * P2P Client IPV4 address allocated via EAPOL-Key exchange.
95      * @hide
96      */
97     public static class P2pGroupClientEapolIpAddressData {
98         /*
99          * The P2P Client IP address.
100          */
101         public final Inet4Address mIpAddressClient;
102         /*
103          * The P2P Group Owner IP address.
104          */
105         public final Inet4Address mIpAddressGo;
106         /*
107          * The subnet that the P2P Group Owner is using.
108          */
109         public final Inet4Address mIpAddressMask;
110 
111         /*
112          * Set P2pClientEapolIpAddressData
113          */
P2pGroupClientEapolIpAddressData(Inet4Address ipAddressClient, Inet4Address ipAddressGo, Inet4Address ipAddressMask)114         public P2pGroupClientEapolIpAddressData(Inet4Address ipAddressClient,
115                 Inet4Address ipAddressGo, Inet4Address ipAddressMask) {
116             this.mIpAddressClient = ipAddressClient;
117             this.mIpAddressGo = ipAddressGo;
118             this.mIpAddressMask = ipAddressMask;
119         }
120     }
121 
122     /**
123      * P2P Client IP address information obtained via EAPOL Handshake.
124      * @hide
125      */
126     public P2pGroupClientEapolIpAddressData p2pClientEapolIpInfo;
127 
128     /** P2P group started string pattern */
129     private static final Pattern groupStartedPattern = Pattern.compile(
130         "ssid=\"(.+)\" " +
131         "freq=(\\d+) " +
132         "(?:psk=)?([0-9a-fA-F]{64})?" +
133         "(?:passphrase=)?(?:\"(.{0,63})\")? " +
134         "go_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})" +
135         " ?(\\[PERSISTENT\\])?"
136     );
137 
WifiP2pGroup()138     public WifiP2pGroup() {
139     }
140 
141     /**
142      * @param supplicantEvent formats supported include
143      *
144      *  P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
145      *  [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|
146      *  passphrase="fKG4jMe3"] go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT]
147      *
148      *  P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED
149      *
150      *  P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13
151      *  bssid=fa:7b:7a:42:82:13 unknown-network
152      *
153      *  P2P-INVITATION-RECEIVED sa=b8:f9:34:2a:c7:9d persistent=0
154      *
155      *  Note: The events formats can be looked up in the wpa_supplicant code
156      *  @hide
157      */
158     @UnsupportedAppUsage
WifiP2pGroup(String supplicantEvent)159     public WifiP2pGroup(String supplicantEvent) throws IllegalArgumentException {
160 
161         String[] tokens = supplicantEvent.split(" ");
162 
163         if (tokens.length < 3) {
164             throw new IllegalArgumentException("Malformed supplicant event");
165         }
166 
167         if (tokens[0].startsWith("P2P-GROUP")) {
168             mInterface = tokens[1];
169             mIsGroupOwner = tokens[2].equals("GO");
170 
171             Matcher match = groupStartedPattern.matcher(supplicantEvent);
172             if (!match.find()) {
173                 return;
174             }
175 
176             mNetworkName = match.group(1);
177             // It throws NumberFormatException if the string cannot be parsed as an integer.
178             mFrequency = Integer.parseInt(match.group(2));
179             // psk is unused right now
180             //String psk = match.group(3);
181             mPassphrase = match.group(4);
182             mOwner = new WifiP2pDevice(match.group(5));
183             if (match.group(6) != null) {
184                 mNetId = NETWORK_ID_PERSISTENT;
185             } else {
186                 mNetId = NETWORK_ID_TEMPORARY;
187             }
188         } else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
189             String sa = null;
190             mNetId = NETWORK_ID_PERSISTENT;
191             for (String token : tokens) {
192                 String[] nameValue = token.split("=");
193                 if (nameValue.length != 2) continue;
194 
195                 if (nameValue[0].equals("sa")) {
196                     sa = nameValue[1];
197 
198                     // set source address into the client list.
199                     WifiP2pDevice dev = new WifiP2pDevice();
200                     dev.deviceAddress = nameValue[1];
201                     mClients.add(dev);
202                     continue;
203                 }
204 
205                 if (nameValue[0].equals("go_dev_addr")) {
206                     mOwner = new WifiP2pDevice(nameValue[1]);
207                     continue;
208                 }
209 
210                 if (nameValue[0].equals("persistent")) {
211                     mNetId = Integer.parseInt(nameValue[1]);
212                     continue;
213                 }
214             }
215         } else {
216             throw new IllegalArgumentException("Malformed supplicant event");
217         }
218     }
219 
220     /** @hide */
setNetworkName(String networkName)221     public void setNetworkName(String networkName) {
222         mNetworkName = networkName;
223     }
224 
225     /**
226      * Get the network name (SSID) of the group. Legacy Wi-Fi clients will discover
227      * the p2p group using the network name.
228      */
getNetworkName()229     public String getNetworkName() {
230         return mNetworkName;
231     }
232 
233     /** @hide */
234     @UnsupportedAppUsage
setIsGroupOwner(boolean isGo)235     public void setIsGroupOwner(boolean isGo) {
236         mIsGroupOwner = isGo;
237     }
238 
239     /** Check whether this device is the group owner of the created p2p group */
isGroupOwner()240     public boolean isGroupOwner() {
241         return mIsGroupOwner;
242     }
243 
244     /** @hide */
setOwner(WifiP2pDevice device)245     public void setOwner(WifiP2pDevice device) {
246         mOwner = device;
247     }
248 
249     /** Get the details of the group owner as a {@link WifiP2pDevice} object */
getOwner()250     public WifiP2pDevice getOwner() {
251         return mOwner;
252     }
253 
254     /** @hide */
addClient(String address)255     public void addClient(String address) {
256         addClient(new WifiP2pDevice(address));
257     }
258 
259     /** @hide */
addClient(WifiP2pDevice device)260     public void addClient(WifiP2pDevice device) {
261         for (WifiP2pDevice client : mClients) {
262             if (client.equals(device)) return;
263         }
264         mClients.add(device);
265     }
266 
267     /** @hide */
removeClient(String address)268     public boolean removeClient(String address) {
269         return mClients.remove(new WifiP2pDevice(address));
270     }
271 
272     /** @hide */
removeClient(WifiP2pDevice device)273     public boolean removeClient(WifiP2pDevice device) {
274         return mClients.remove(device);
275     }
276 
277     /** @hide */
278     @UnsupportedAppUsage
isClientListEmpty()279     public boolean isClientListEmpty() {
280         return mClients.size() == 0;
281     }
282 
283     /**
284      * Returns {@code true} if the device is part of the group, {@code false} otherwise.
285      *
286      * @hide
287      */
contains(@ullable WifiP2pDevice device)288     public boolean contains(@Nullable WifiP2pDevice device) {
289         return mOwner.equals(device) || mClients.contains(device);
290     }
291 
292     /** Get the list of clients currently part of the p2p group */
getClientList()293     public Collection<WifiP2pDevice> getClientList() {
294         return Collections.unmodifiableCollection(mClients);
295     }
296 
297     /** @hide */
setPassphrase(String passphrase)298     public void setPassphrase(String passphrase) {
299         mPassphrase = passphrase;
300     }
301 
302     /**
303      * Get the passphrase of the group. This function will return a valid passphrase only
304      * at the group owner. Legacy Wi-Fi clients will need this passphrase alongside
305      * network name obtained from {@link #getNetworkName()} to join the group
306      */
getPassphrase()307     public String getPassphrase() {
308         return mPassphrase;
309     }
310 
311     /** @hide */
312     @UnsupportedAppUsage
setInterface(String intf)313     public void setInterface(String intf) {
314         mInterface = intf;
315     }
316 
317     /** Get the interface name on which the group is created */
getInterface()318     public String getInterface() {
319         return mInterface;
320     }
321 
322     /** The network ID of the P2P group in wpa_supplicant. */
getNetworkId()323     public int getNetworkId() {
324         return mNetId;
325     }
326 
327     /** @hide */
328     @UnsupportedAppUsage
setNetworkId(int netId)329     public void setNetworkId(int netId) {
330         this.mNetId = netId;
331     }
332 
333     /** Get the operating frequency (in MHz) of the p2p group */
getFrequency()334     public int getFrequency() {
335         return mFrequency;
336     }
337 
338     /** @hide */
setFrequency(int freq)339     public void setFrequency(int freq) {
340         this.mFrequency = freq;
341     }
342 
toString()343     public String toString() {
344         StringBuffer sbuf = new StringBuffer();
345         sbuf.append("network: ").append(mNetworkName);
346         sbuf.append("\n isGO: ").append(mIsGroupOwner);
347         sbuf.append("\n GO: ").append(mOwner);
348         for (WifiP2pDevice client : mClients) {
349             sbuf.append("\n Client: ").append(client);
350         }
351         sbuf.append("\n interface: ").append(mInterface);
352         sbuf.append("\n networkId: ").append(mNetId);
353         sbuf.append("\n frequency: ").append(mFrequency);
354         return sbuf.toString();
355     }
356 
357     /** Implement the Parcelable interface */
describeContents()358     public int describeContents() {
359         return 0;
360     }
361 
362     /** copy constructor */
WifiP2pGroup(WifiP2pGroup source)363     public WifiP2pGroup(WifiP2pGroup source) {
364         if (source != null) {
365             mNetworkName = source.getNetworkName();
366             mOwner = new WifiP2pDevice(source.getOwner());
367             mIsGroupOwner = source.mIsGroupOwner;
368             for (WifiP2pDevice d : source.getClientList()) mClients.add(d);
369             mPassphrase = source.getPassphrase();
370             mInterface = source.getInterface();
371             mNetId = source.getNetworkId();
372             mFrequency = source.getFrequency();
373         }
374     }
375 
376     /** Implement the Parcelable interface */
writeToParcel(Parcel dest, int flags)377     public void writeToParcel(Parcel dest, int flags) {
378         dest.writeString(mNetworkName);
379         dest.writeParcelable(mOwner, flags);
380         dest.writeByte(mIsGroupOwner ? (byte) 1: (byte) 0);
381         dest.writeInt(mClients.size());
382         for (WifiP2pDevice client : mClients) {
383             dest.writeParcelable(client, flags);
384         }
385         dest.writeString(mPassphrase);
386         dest.writeString(mInterface);
387         dest.writeInt(mNetId);
388         dest.writeInt(mFrequency);
389     }
390 
391     /** Implement the Parcelable interface */
392     public static final @android.annotation.NonNull Creator<WifiP2pGroup> CREATOR =
393         new Creator<WifiP2pGroup>() {
394             public WifiP2pGroup createFromParcel(Parcel in) {
395                 WifiP2pGroup group = new WifiP2pGroup();
396                 group.setNetworkName(in.readString());
397                 group.setOwner((WifiP2pDevice)in.readParcelable(null));
398                 group.setIsGroupOwner(in.readByte() == (byte)1);
399                 int clientCount = in.readInt();
400                 for (int i=0; i<clientCount; i++) {
401                     group.addClient((WifiP2pDevice) in.readParcelable(null));
402                 }
403                 group.setPassphrase(in.readString());
404                 group.setInterface(in.readString());
405                 group.setNetworkId(in.readInt());
406                 group.setFrequency(in.readInt());
407                 return group;
408             }
409 
410             public WifiP2pGroup[] newArray(int size) {
411                 return new WifiP2pGroup[size];
412             }
413         };
414 }
415