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 mNetId = Integer.parseInt(nameValue[1]); 150 continue; 151 } 152 } 153 } else { 154 throw new IllegalArgumentException("Malformed supplicant event"); 155 } 156 } 157 158 /** @hide */ setNetworkName(String networkName)159 public void setNetworkName(String networkName) { 160 mNetworkName = networkName; 161 } 162 163 /** 164 * Get the network name (SSID) of the group. Legacy Wi-Fi clients will discover 165 * the p2p group using the network name. 166 */ getNetworkName()167 public String getNetworkName() { 168 return mNetworkName; 169 } 170 171 /** @hide */ setIsGroupOwner(boolean isGo)172 public void setIsGroupOwner(boolean isGo) { 173 mIsGroupOwner = isGo; 174 } 175 176 /** Check whether this device is the group owner of the created p2p group */ isGroupOwner()177 public boolean isGroupOwner() { 178 return mIsGroupOwner; 179 } 180 181 /** @hide */ setOwner(WifiP2pDevice device)182 public void setOwner(WifiP2pDevice device) { 183 mOwner = device; 184 } 185 186 /** Get the details of the group owner as a {@link WifiP2pDevice} object */ getOwner()187 public WifiP2pDevice getOwner() { 188 return mOwner; 189 } 190 191 /** @hide */ addClient(String address)192 public void addClient(String address) { 193 addClient(new WifiP2pDevice(address)); 194 } 195 196 /** @hide */ addClient(WifiP2pDevice device)197 public void addClient(WifiP2pDevice device) { 198 for (WifiP2pDevice client : mClients) { 199 if (client.equals(device)) return; 200 } 201 mClients.add(device); 202 } 203 204 /** @hide */ removeClient(String address)205 public boolean removeClient(String address) { 206 return mClients.remove(new WifiP2pDevice(address)); 207 } 208 209 /** @hide */ removeClient(WifiP2pDevice device)210 public boolean removeClient(WifiP2pDevice device) { 211 return mClients.remove(device); 212 } 213 214 /** @hide */ isClientListEmpty()215 public boolean isClientListEmpty() { 216 return mClients.size() == 0; 217 } 218 219 /** @hide Returns {@code true} if the device is part of the group */ contains(WifiP2pDevice device)220 public boolean contains(WifiP2pDevice device) { 221 if (mOwner.equals(device) || mClients.contains(device)) return true; 222 return false; 223 } 224 225 /** Get the list of clients currently part of the p2p group */ getClientList()226 public Collection<WifiP2pDevice> getClientList() { 227 return Collections.unmodifiableCollection(mClients); 228 } 229 230 /** @hide */ setPassphrase(String passphrase)231 public void setPassphrase(String passphrase) { 232 mPassphrase = passphrase; 233 } 234 235 /** 236 * Get the passphrase of the group. This function will return a valid passphrase only 237 * at the group owner. Legacy Wi-Fi clients will need this passphrase alongside 238 * network name obtained from {@link #getNetworkName()} to join the group 239 */ getPassphrase()240 public String getPassphrase() { 241 return mPassphrase; 242 } 243 244 /** @hide */ setInterface(String intf)245 public void setInterface(String intf) { 246 mInterface = intf; 247 } 248 249 /** Get the interface name on which the group is created */ getInterface()250 public String getInterface() { 251 return mInterface; 252 } 253 254 /** @hide */ getNetworkId()255 public int getNetworkId() { 256 return mNetId; 257 } 258 259 /** @hide */ setNetworkId(int netId)260 public void setNetworkId(int netId) { 261 this.mNetId = netId; 262 } 263 toString()264 public String toString() { 265 StringBuffer sbuf = new StringBuffer(); 266 sbuf.append("network: ").append(mNetworkName); 267 sbuf.append("\n isGO: ").append(mIsGroupOwner); 268 sbuf.append("\n GO: ").append(mOwner); 269 for (WifiP2pDevice client : mClients) { 270 sbuf.append("\n Client: ").append(client); 271 } 272 sbuf.append("\n interface: ").append(mInterface); 273 sbuf.append("\n networkId: ").append(mNetId); 274 return sbuf.toString(); 275 } 276 277 /** Implement the Parcelable interface */ describeContents()278 public int describeContents() { 279 return 0; 280 } 281 282 /** copy constructor */ WifiP2pGroup(WifiP2pGroup source)283 public WifiP2pGroup(WifiP2pGroup source) { 284 if (source != null) { 285 mNetworkName = source.getNetworkName(); 286 mOwner = new WifiP2pDevice(source.getOwner()); 287 mIsGroupOwner = source.mIsGroupOwner; 288 for (WifiP2pDevice d : source.getClientList()) mClients.add(d); 289 mPassphrase = source.getPassphrase(); 290 mInterface = source.getInterface(); 291 mNetId = source.getNetworkId(); 292 } 293 } 294 295 /** Implement the Parcelable interface */ writeToParcel(Parcel dest, int flags)296 public void writeToParcel(Parcel dest, int flags) { 297 dest.writeString(mNetworkName); 298 dest.writeParcelable(mOwner, flags); 299 dest.writeByte(mIsGroupOwner ? (byte) 1: (byte) 0); 300 dest.writeInt(mClients.size()); 301 for (WifiP2pDevice client : mClients) { 302 dest.writeParcelable(client, flags); 303 } 304 dest.writeString(mPassphrase); 305 dest.writeString(mInterface); 306 dest.writeInt(mNetId); 307 } 308 309 /** Implement the Parcelable interface */ 310 public static final Creator<WifiP2pGroup> CREATOR = 311 new Creator<WifiP2pGroup>() { 312 public WifiP2pGroup createFromParcel(Parcel in) { 313 WifiP2pGroup group = new WifiP2pGroup(); 314 group.setNetworkName(in.readString()); 315 group.setOwner((WifiP2pDevice)in.readParcelable(null)); 316 group.setIsGroupOwner(in.readByte() == (byte)1); 317 int clientCount = in.readInt(); 318 for (int i=0; i<clientCount; i++) { 319 group.addClient((WifiP2pDevice) in.readParcelable(null)); 320 } 321 group.setPassphrase(in.readString()); 322 group.setInterface(in.readString()); 323 group.setNetworkId(in.readInt()); 324 return group; 325 } 326 327 public WifiP2pGroup[] newArray(int size) { 328 return new WifiP2pGroup[size]; 329 } 330 }; 331 } 332