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