wps-ap-nfc.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #!/usr/bin/python
  2. #
  3. # Example nfcpy to hostapd wrapper for WPS NFC operations
  4. # Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
  5. #
  6. # This software may be distributed under the terms of the BSD license.
  7. # See README for more details.
  8. import os
  9. import sys
  10. import time
  11. import nfc
  12. import nfc.ndef
  13. import nfc.llcp
  14. import nfc.handover
  15. import logging
  16. logging.basicConfig()
  17. import wpactrl
  18. wpas_ctrl = '/var/run/hostapd'
  19. def wpas_connect():
  20. ifaces = []
  21. if os.path.isdir(wpas_ctrl):
  22. try:
  23. ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
  24. except OSError, error:
  25. print "Could not find hostapd: ", error
  26. return None
  27. if len(ifaces) < 1:
  28. print "No hostapd control interface found"
  29. return None
  30. for ctrl in ifaces:
  31. try:
  32. wpas = wpactrl.WPACtrl(ctrl)
  33. return wpas
  34. except wpactrl.error, error:
  35. print "Error: ", error
  36. pass
  37. return None
  38. def wpas_tag_read(message):
  39. wpas = wpas_connect()
  40. if (wpas == None):
  41. return
  42. print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
  43. def wpas_get_config_token():
  44. wpas = wpas_connect()
  45. if (wpas == None):
  46. return None
  47. return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
  48. def wpas_get_password_token():
  49. wpas = wpas_connect()
  50. if (wpas == None):
  51. return None
  52. return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
  53. def wpas_get_handover_req():
  54. wpas = wpas_connect()
  55. if (wpas == None):
  56. return None
  57. return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
  58. def wpas_put_handover_sel(message):
  59. wpas = wpas_connect()
  60. if (wpas == None):
  61. return
  62. print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
  63. def wps_handover_init(peer):
  64. print "Trying to initiate WPS handover"
  65. data = wpas_get_handover_req()
  66. if (data == None):
  67. print "Could not get handover request message from hostapd"
  68. return
  69. print "Handover request from hostapd: " + data.encode("hex")
  70. message = nfc.ndef.Message(data)
  71. print "Parsed handover request: " + message.pretty()
  72. nfc.llcp.activate(peer);
  73. time.sleep(0.5)
  74. client = nfc.handover.HandoverClient()
  75. try:
  76. print "Trying handover";
  77. client.connect()
  78. print "Connected for handover"
  79. except nfc.llcp.ConnectRefused:
  80. print "Handover connection refused"
  81. nfc.llcp.shutdown()
  82. client.close()
  83. return
  84. print "Sending handover request"
  85. if not client.send(message):
  86. print "Failed to send handover request"
  87. print "Receiving handover response"
  88. message = client._recv()
  89. print "Handover select received"
  90. print message.pretty()
  91. wpas_put_handover_sel(message)
  92. print "Remove peer"
  93. nfc.llcp.shutdown()
  94. client.close()
  95. print "Done with handover"
  96. def wps_tag_read(tag):
  97. if len(tag.ndef.message):
  98. message = nfc.ndef.Message(tag.ndef.message)
  99. print "message type " + message.type
  100. for record in message:
  101. print "record type " + record.type
  102. if record.type == "application/vnd.wfa.wsc":
  103. print "WPS tag - send to hostapd"
  104. wpas_tag_read(tag.ndef.message)
  105. break
  106. else:
  107. print "Empty tag"
  108. print "Remove tag"
  109. while tag.is_present:
  110. time.sleep(0.1)
  111. def wps_write_config_tag(clf):
  112. print "Write WPS config token"
  113. data = wpas_get_config_token()
  114. if (data == None):
  115. print "Could not get WPS config token from hostapd"
  116. return
  117. print "Touch an NFC tag"
  118. while True:
  119. tag = clf.poll()
  120. if tag == None:
  121. time.sleep(0.1)
  122. continue
  123. break
  124. print "Tag found - writing"
  125. tag.ndef.message = data
  126. print "Done - remove tag"
  127. while tag.is_present:
  128. time.sleep(0.1)
  129. def wps_write_password_tag(clf):
  130. print "Write WPS password token"
  131. data = wpas_get_password_token()
  132. if (data == None):
  133. print "Could not get WPS password token from hostapd"
  134. return
  135. print "Touch an NFC tag"
  136. while True:
  137. tag = clf.poll()
  138. if tag == None:
  139. time.sleep(0.1)
  140. continue
  141. break
  142. print "Tag found - writing"
  143. tag.ndef.message = data
  144. print "Done - remove tag"
  145. while tag.is_present:
  146. time.sleep(0.1)
  147. def main():
  148. clf = nfc.ContactlessFrontend()
  149. try:
  150. if len(sys.argv) > 1 and sys.argv[1] == "write-config":
  151. wps_write_config_tag(clf)
  152. raise SystemExit
  153. if len(sys.argv) > 1 and sys.argv[1] == "write-password":
  154. wps_write_password_tag(clf)
  155. raise SystemExit
  156. while True:
  157. print "Waiting for a tag or peer to be touched"
  158. while True:
  159. general_bytes = nfc.llcp.startup({})
  160. tag = clf.poll(general_bytes)
  161. if tag == None:
  162. continue
  163. if isinstance(tag, nfc.DEP):
  164. wps_handover_init(tag)
  165. break
  166. if tag.ndef:
  167. wps_tag_read(tag)
  168. break
  169. if tag:
  170. print "Not an NDEF tag - remove tag"
  171. while tag.is_present:
  172. time.sleep(0.1)
  173. break
  174. except KeyboardInterrupt:
  175. raise SystemExit
  176. finally:
  177. clf.close()
  178. raise SystemExit
  179. if __name__ == '__main__':
  180. main()