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