ndef.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup
  3. * Reference is "NFCForum-TS-NDEF_1.0 2006-07-24".
  4. * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Alternatively, this software may be distributed under the terms of BSD
  11. * license.
  12. *
  13. * See README and COPYING for more details.
  14. */
  15. #include "includes.h"
  16. #include "common.h"
  17. #include "wps/wps.h"
  18. #include "wps/wps_i.h"
  19. #define FLAG_MESSAGE_BEGIN (1 << 7)
  20. #define FLAG_MESSAGE_END (1 << 6)
  21. #define FLAG_CHUNK (1 << 5)
  22. #define FLAG_SHORT_RECORD (1 << 4)
  23. #define FLAG_ID_LENGTH_PRESENT (1 << 3)
  24. #define FLAG_TNF_RFC2046 (0x02)
  25. struct ndef_record {
  26. u8 *type;
  27. u8 *id;
  28. u8 *payload;
  29. u8 type_length;
  30. u8 id_length;
  31. u32 payload_length;
  32. u32 total_length;
  33. };
  34. static char wifi_handover_type[] = "application/vnd.wfa.wsc";
  35. static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record)
  36. {
  37. u8 *pos = data + 1;
  38. if (size < 2)
  39. return -1;
  40. record->type_length = *pos++;
  41. if (data[0] & FLAG_SHORT_RECORD) {
  42. if (size < 3)
  43. return -1;
  44. record->payload_length = *pos++;
  45. } else {
  46. if (size < 6)
  47. return -1;
  48. record->payload_length = ntohl(*(u32 *)pos);
  49. pos += sizeof(u32);
  50. }
  51. if (data[0] & FLAG_ID_LENGTH_PRESENT) {
  52. if ((int) size < pos - data + 1)
  53. return -1;
  54. record->id_length = *pos++;
  55. } else
  56. record->id_length = 0;
  57. record->type = record->type_length == 0 ? NULL : pos;
  58. pos += record->type_length;
  59. record->id = record->id_length == 0 ? NULL : pos;
  60. pos += record->id_length;
  61. record->payload = record->payload_length == 0 ? NULL : pos;
  62. pos += record->payload_length;
  63. record->total_length = pos - data;
  64. if (record->total_length > size)
  65. return -1;
  66. return 0;
  67. }
  68. static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
  69. int (*filter)(struct ndef_record *))
  70. {
  71. struct ndef_record record;
  72. int len = wpabuf_len(buf);
  73. u8 *data = wpabuf_mhead(buf);
  74. while (len > 0) {
  75. if (ndef_parse_record(data, len, &record) < 0) {
  76. wpa_printf(MSG_ERROR, "NDEF : Failed to parse");
  77. return NULL;
  78. }
  79. if (filter == NULL || filter(&record))
  80. return wpabuf_alloc_copy(record.payload,
  81. record.payload_length);
  82. data += record.total_length;
  83. len -= record.total_length;
  84. }
  85. wpa_printf(MSG_ERROR, "NDEF : Record not found");
  86. return NULL;
  87. }
  88. static struct wpabuf * ndef_build_record(u8 flags, void *type,
  89. u8 type_length, void *id,
  90. u8 id_length, void *payload,
  91. u32 payload_length)
  92. {
  93. struct wpabuf *record;
  94. size_t total_len;
  95. int short_record;
  96. u8 local_flag;
  97. short_record = payload_length < 256 ? 1 : 0;
  98. total_len = 2; /* flag + type length */
  99. /* payload length */
  100. total_len += short_record ? sizeof(u8) : sizeof(u32);
  101. if (id_length > 0)
  102. total_len += 1;
  103. total_len += type_length + id_length + payload_length;
  104. record = wpabuf_alloc(total_len);
  105. if (record == NULL) {
  106. wpa_printf(MSG_ERROR, "NDEF : Failed to allocate "
  107. "record for build");
  108. return NULL;
  109. }
  110. local_flag = flags;
  111. if (id_length > 0)
  112. local_flag |= FLAG_ID_LENGTH_PRESENT;
  113. if (short_record)
  114. local_flag |= FLAG_SHORT_RECORD;
  115. wpabuf_put_u8(record, local_flag);
  116. wpabuf_put_u8(record, type_length);
  117. if (short_record)
  118. wpabuf_put_u8(record, payload_length);
  119. else
  120. wpabuf_put_be32(record, payload_length);
  121. if (id_length > 0)
  122. wpabuf_put_u8(record, id_length);
  123. wpabuf_put_data(record, type, type_length);
  124. wpabuf_put_data(record, id, id_length);
  125. wpabuf_put_data(record, payload, payload_length);
  126. return record;
  127. }
  128. static int wifi_filter(struct ndef_record *record)
  129. {
  130. if (record->type_length != os_strlen(wifi_handover_type))
  131. return 0;
  132. if (os_memcmp(record->type, wifi_handover_type,
  133. os_strlen(wifi_handover_type)) != 0)
  134. return 0;
  135. return 1;
  136. }
  137. struct wpabuf * ndef_parse_wifi(struct wpabuf *buf)
  138. {
  139. return ndef_parse_records(buf, wifi_filter);
  140. }
  141. struct wpabuf * ndef_build_wifi(struct wpabuf *buf)
  142. {
  143. return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
  144. FLAG_TNF_RFC2046, wifi_handover_type,
  145. os_strlen(wifi_handover_type), NULL, 0,
  146. wpabuf_mhead(buf), wpabuf_len(buf));
  147. }