Home | History | Annotate | Download | only in hostapd
      1 #!/usr/bin/python
      2 #
      3 # Example nfcpy to hostapd wrapper for WPS NFC operations
      4 # Copyright (c) 2012-2013, Jouni Malinen <j (at] w1.fi>
      5 #
      6 # This software may be distributed under the terms of the BSD license.
      7 # See README for more details.
      8 
      9 import os
     10 import sys
     11 import time
     12 
     13 import nfc
     14 import nfc.ndef
     15 import nfc.llcp
     16 import nfc.handover
     17 
     18 import logging
     19 logging.basicConfig()
     20 
     21 import wpaspy
     22 
     23 wpas_ctrl = '/var/run/hostapd'
     24 
     25 def wpas_connect():
     26     ifaces = []
     27     if os.path.isdir(wpas_ctrl):
     28         try:
     29             ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
     30         except OSError, error:
     31             print "Could not find hostapd: ", error
     32             return None
     33 
     34     if len(ifaces) < 1:
     35         print "No hostapd control interface found"
     36         return None
     37 
     38     for ctrl in ifaces:
     39         try:
     40             wpas = wpaspy.Ctrl(ctrl)
     41             return wpas
     42         except Exception, e:
     43             pass
     44     return None
     45 
     46 
     47 def wpas_tag_read(message):
     48     wpas = wpas_connect()
     49     if (wpas == None):
     50         return
     51     print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
     52 
     53 
     54 def wpas_get_config_token():
     55     wpas = wpas_connect()
     56     if (wpas == None):
     57         return None
     58     return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
     59 
     60 
     61 def wpas_get_password_token():
     62     wpas = wpas_connect()
     63     if (wpas == None):
     64         return None
     65     return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
     66 
     67 
     68 def wpas_get_handover_sel():
     69     wpas = wpas_connect()
     70     if (wpas == None):
     71         return None
     72     return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
     73 
     74 
     75 def wpas_report_handover(req, sel):
     76     wpas = wpas_connect()
     77     if (wpas == None):
     78         return None
     79     return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
     80                         str(req).encode("hex") + " " +
     81                         str(sel).encode("hex"))
     82 
     83 
     84 class HandoverServer(nfc.handover.HandoverServer):
     85     def __init__(self):
     86         super(HandoverServer, self).__init__()
     87 
     88     def process_request(self, request):
     89         print "HandoverServer - request received"
     90         print "Parsed handover request: " + request.pretty()
     91 
     92         sel = nfc.ndef.HandoverSelectMessage(version="1.2")
     93 
     94         for carrier in request.carriers:
     95             print "Remote carrier type: " + carrier.type
     96             if carrier.type == "application/vnd.wfa.wsc":
     97                 print "WPS carrier type match - add WPS carrier record"
     98                 self.received_carrier = carrier.record
     99                 data = wpas_get_handover_sel()
    100                 if data is None:
    101                     print "Could not get handover select carrier record from hostapd"
    102                     continue
    103                 print "Handover select carrier record from hostapd:"
    104                 print data.encode("hex")
    105                 self.sent_carrier = data
    106 
    107                 message = nfc.ndef.Message(data);
    108                 sel.add_carrier(message[0], "active", message[1:])
    109 
    110         print "Handover select:"
    111         print sel.pretty()
    112         print str(sel).encode("hex")
    113 
    114         print "Sending handover select"
    115         return sel
    116 
    117 
    118 def wps_handover_resp(peer):
    119     print "Trying to handle WPS handover"
    120 
    121     srv = HandoverServer()
    122     srv.sent_carrier = None
    123 
    124     nfc.llcp.activate(peer);
    125 
    126     try:
    127         print "Trying handover";
    128         srv.start()
    129         print "Wait for disconnect"
    130         while nfc.llcp.connected():
    131             time.sleep(0.1)
    132         print "Disconnected after handover"
    133     except nfc.llcp.ConnectRefused:
    134         print "Handover connection refused"
    135         nfc.llcp.shutdown()
    136         return
    137 
    138     if srv.sent_carrier:
    139         wpas_report_handover(srv.received_carrier, srv.sent_carrier)
    140 
    141     print "Remove peer"
    142     nfc.llcp.shutdown()
    143     print "Done with handover"
    144 
    145 
    146 def wps_tag_read(tag):
    147     if len(tag.ndef.message):
    148         message = nfc.ndef.Message(tag.ndef.message)
    149         print "message type " + message.type
    150 
    151         for record in message:
    152             print "record type " + record.type
    153             if record.type == "application/vnd.wfa.wsc":
    154                 print "WPS tag - send to hostapd"
    155                 wpas_tag_read(tag.ndef.message)
    156                 break
    157     else:
    158         print "Empty tag"
    159 
    160     print "Remove tag"
    161     while tag.is_present:
    162         time.sleep(0.1)
    163 
    164 
    165 def wps_write_config_tag(clf):
    166     print "Write WPS config token"
    167     data = wpas_get_config_token()
    168     if (data == None):
    169         print "Could not get WPS config token from hostapd"
    170         return
    171 
    172     print "Touch an NFC tag"
    173     while True:
    174         tag = clf.poll()
    175         if tag == None:
    176             time.sleep(0.1)
    177             continue
    178         break
    179 
    180     print "Tag found - writing"
    181     tag.ndef.message = data
    182     print "Done - remove tag"
    183     while tag.is_present:
    184         time.sleep(0.1)
    185 
    186 
    187 def wps_write_password_tag(clf):
    188     print "Write WPS password token"
    189     data = wpas_get_password_token()
    190     if (data == None):
    191         print "Could not get WPS password token from hostapd"
    192         return
    193 
    194     print "Touch an NFC tag"
    195     while True:
    196         tag = clf.poll()
    197         if tag == None:
    198             time.sleep(0.1)
    199             continue
    200         break
    201 
    202     print "Tag found - writing"
    203     tag.ndef.message = data
    204     print "Done - remove tag"
    205     while tag.is_present:
    206         time.sleep(0.1)
    207 
    208 
    209 def find_peer(clf):
    210     while True:
    211         if nfc.llcp.connected():
    212             print "LLCP connected"
    213         general_bytes = nfc.llcp.startup({})
    214         peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
    215         if isinstance(peer, nfc.DEP):
    216             print "listen -> DEP";
    217             if peer.general_bytes.startswith("Ffm"):
    218                 print "Found DEP"
    219                 return peer
    220             print "mismatch in general_bytes"
    221             print peer.general_bytes
    222 
    223         peer = clf.poll(general_bytes)
    224         if isinstance(peer, nfc.DEP):
    225             print "poll -> DEP";
    226             if peer.general_bytes.startswith("Ffm"):
    227                 print "Found DEP"
    228                 return peer
    229             print "mismatch in general_bytes"
    230             print peer.general_bytes
    231 
    232         if peer:
    233             print "Found tag"
    234             return peer
    235 
    236 
    237 def main():
    238     clf = nfc.ContactlessFrontend()
    239 
    240     try:
    241         if len(sys.argv) > 1 and sys.argv[1] == "write-config":
    242             wps_write_config_tag(clf)
    243             raise SystemExit
    244 
    245         if len(sys.argv) > 1 and sys.argv[1] == "write-password":
    246             wps_write_password_tag(clf)
    247             raise SystemExit
    248 
    249         while True:
    250             print "Waiting for a tag or peer to be touched"
    251 
    252             tag = find_peer(clf)
    253             if isinstance(tag, nfc.DEP):
    254                 wps_handover_resp(tag)
    255                 continue
    256 
    257             if tag.ndef:
    258                 wps_tag_read(tag)
    259                 continue
    260 
    261             print "Not an NDEF tag - remove tag"
    262             while tag.is_present:
    263                 time.sleep(0.1)
    264 
    265     except KeyboardInterrupt:
    266         raise SystemExit
    267     finally:
    268         clf.close()
    269 
    270     raise SystemExit
    271 
    272 if __name__ == '__main__':
    273     main()
    274