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