Home | History | Annotate | Download | only in p2p
      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 
     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      */
     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 */
    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      */
    168     public String getNetworkName() {
    169         return mNetworkName;
    170     }
    171 
    172     /** @hide */
    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 */
    178     public boolean isGroupOwner() {
    179         return mIsGroupOwner;
    180     }
    181 
    182     /** @hide */
    183     public void setOwner(WifiP2pDevice device) {
    184         mOwner = device;
    185     }
    186 
    187     /** Get the details of the group owner as a {@link WifiP2pDevice} object */
    188     public WifiP2pDevice getOwner() {
    189         return mOwner;
    190     }
    191 
    192     /** @hide */
    193     public void addClient(String address) {
    194         addClient(new WifiP2pDevice(address));
    195     }
    196 
    197     /** @hide */
    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 */
    206     public boolean removeClient(String address) {
    207         return mClients.remove(new WifiP2pDevice(address));
    208     }
    209 
    210     /** @hide */
    211     public boolean removeClient(WifiP2pDevice device) {
    212         return mClients.remove(device);
    213     }
    214 
    215     /** @hide */
    216     public boolean isClientListEmpty() {
    217         return mClients.size() == 0;
    218     }
    219 
    220     /** @hide Returns {@code true} if the device is part of the group */
    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 */
    227     public Collection<WifiP2pDevice> getClientList() {
    228         return Collections.unmodifiableCollection(mClients);
    229     }
    230 
    231     /** @hide */
    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      */
    241     public String getPassphrase() {
    242         return mPassphrase;
    243     }
    244 
    245     /** @hide */
    246     public void setInterface(String intf) {
    247         mInterface = intf;
    248     }
    249 
    250     /** Get the interface name on which the group is created */
    251     public String getInterface() {
    252         return mInterface;
    253     }
    254 
    255     /** @hide */
    256     public int getNetworkId() {
    257         return mNetId;
    258     }
    259 
    260     /** @hide */
    261     public void setNetworkId(int netId) {
    262         this.mNetId = netId;
    263     }
    264 
    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 */
    279     public int describeContents() {
    280         return 0;
    281     }
    282 
    283     /** copy constructor */
    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 */
    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