/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 266 lines · 131 code · 43 blank · 92 comment · 44 complexity · 78b857add9b9ba583c2dd83e1e788aa9 MD5 · raw file

  1. /*
  2. * rfcomm_sdp.c
  3. *
  4. * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  17. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  20. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26. * SUCH DAMAGE.
  27. *
  28. * $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $
  29. * $FreeBSD$
  30. */
  31. #include <bluetooth.h>
  32. #include <errno.h>
  33. #include <sdp.h>
  34. #include <stdio.h>
  35. #undef PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE
  36. #define PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 256
  37. #undef PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE
  38. #define PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 12
  39. static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end,
  40. int *channel, int *error);
  41. /*
  42. * Lookup RFCOMM channel number in the Protocol Descriptor List
  43. */
  44. #undef rfcomm_channel_lookup_exit
  45. #define rfcomm_channel_lookup_exit(e) { \
  46. if (error != NULL) \
  47. *error = (e); \
  48. if (ss != NULL) { \
  49. sdp_close(ss); \
  50. ss = NULL; \
  51. } \
  52. return (((e) == 0)? 0 : -1); \
  53. }
  54. int
  55. rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
  56. int service, int *channel, int *error)
  57. {
  58. uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE];
  59. void *ss = NULL;
  60. uint16_t serv = (uint16_t) service;
  61. uint32_t attr = SDP_ATTR_RANGE(
  62. SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
  63. SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
  64. sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
  65. uint32_t type, len;
  66. if (local == NULL)
  67. local = NG_HCI_BDADDR_ANY;
  68. if (remote == NULL || channel == NULL)
  69. rfcomm_channel_lookup_exit(EINVAL);
  70. if ((ss = sdp_open(local, remote)) == NULL)
  71. rfcomm_channel_lookup_exit(ENOMEM);
  72. if (sdp_error(ss) != 0)
  73. rfcomm_channel_lookup_exit(sdp_error(ss));
  74. if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
  75. rfcomm_channel_lookup_exit(sdp_error(ss));
  76. if (proto.flags != SDP_ATTR_OK)
  77. rfcomm_channel_lookup_exit(ENOATTR);
  78. sdp_close(ss);
  79. ss = NULL;
  80. /*
  81. * If it is possible for more than one kind of protocol stack to be
  82. * used to gain access to the service, the ProtocolDescriptorList
  83. * takes the form of a data element alternative. We always use the
  84. * first protocol stack.
  85. *
  86. * A minimal Protocol Descriptor List for RFCOMM based service would
  87. * look like
  88. *
  89. * seq8 len8 - 2 bytes
  90. * seq8 len8 - 2 bytes
  91. * uuid16 value16 - 3 bytes L2CAP
  92. * seq8 len8 - 2 bytes
  93. * uuid16 value16 - 3 bytes RFCOMM
  94. * uint8 value8 - 2 bytes RFCOMM param #1
  95. * =========
  96. * 14 bytes
  97. *
  98. * Lets not count first [seq8 len8] wrapper, so the minimal size of
  99. * the Protocol Descriptor List (the data we are actually interested
  100. * in) for RFCOMM based service would be 12 bytes.
  101. */
  102. if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
  103. rfcomm_channel_lookup_exit(EINVAL);
  104. SDP_GET8(type, proto.value);
  105. if (type == SDP_DATA_ALT8) {
  106. SDP_GET8(len, proto.value);
  107. } else if (type == SDP_DATA_ALT16) {
  108. SDP_GET16(len, proto.value);
  109. } else if (type == SDP_DATA_ALT32) {
  110. SDP_GET32(len, proto.value);
  111. } else
  112. len = 0;
  113. if (len > 0)
  114. SDP_GET8(type, proto.value);
  115. switch (type) {
  116. case SDP_DATA_SEQ8:
  117. SDP_GET8(len, proto.value);
  118. break;
  119. case SDP_DATA_SEQ16:
  120. SDP_GET16(len, proto.value);
  121. break;
  122. case SDP_DATA_SEQ32:
  123. SDP_GET32(len, proto.value);
  124. break;
  125. default:
  126. rfcomm_channel_lookup_exit(ENOATTR);
  127. /* NOT REACHED */
  128. }
  129. if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
  130. rfcomm_channel_lookup_exit(EINVAL);
  131. return (rfcomm_proto_list_parse(proto.value,
  132. buffer + proto.vlen, channel, error));
  133. }
  134. /*
  135. * Parse protocol descriptor list
  136. *
  137. * The ProtocolDescriptorList attribute describes one or more protocol
  138. * stacks that may be used to gain access to the service described by
  139. * the service record. If the ProtocolDescriptorList describes a single
  140. * stack, it takes the form of a data element sequence in which each
  141. * element of the sequence is a protocol descriptor.
  142. */
  143. #undef rfcomm_proto_list_parse_exit
  144. #define rfcomm_proto_list_parse_exit(e) { \
  145. if (error != NULL) \
  146. *error = (e); \
  147. return (((e) == 0)? 0 : -1); \
  148. }
  149. static int
  150. rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end,
  151. int *channel, int *error)
  152. {
  153. int type, len, value;
  154. while (start < end) {
  155. /*
  156. * Parse protocol descriptor
  157. *
  158. * A protocol descriptor identifies a communications protocol
  159. * and provides protocol specific parameters. A protocol
  160. * descriptor is represented as a data element sequence. The
  161. * first data element in the sequence must be the UUID that
  162. * identifies the protocol. Additional data elements optionally
  163. * provide protocol specific information, such as the L2CAP
  164. * protocol/service multiplexer (PSM) and the RFCOMM server
  165. * channel number (CN).
  166. */
  167. /* We must have at least one byte (type) */
  168. if (end - start < 1)
  169. rfcomm_proto_list_parse_exit(EINVAL)
  170. SDP_GET8(type, start);
  171. switch (type) {
  172. case SDP_DATA_SEQ8:
  173. SDP_GET8(len, start);
  174. break;
  175. case SDP_DATA_SEQ16:
  176. SDP_GET16(len, start);
  177. break;
  178. case SDP_DATA_SEQ32:
  179. SDP_GET32(len, start);
  180. break;
  181. default:
  182. rfcomm_proto_list_parse_exit(ENOATTR)
  183. /* NOT REACHED */
  184. }
  185. /* We must have at least 3 bytes (type + UUID16) */
  186. if (end - start < 3)
  187. rfcomm_proto_list_parse_exit(EINVAL);
  188. /* Get protocol UUID */
  189. SDP_GET8(type, start); len -= sizeof(uint8_t);
  190. switch (type) {
  191. case SDP_DATA_UUID16:
  192. SDP_GET16(value, start); len -= sizeof(uint16_t);
  193. if (value != SDP_UUID_PROTOCOL_RFCOMM)
  194. goto next_protocol;
  195. break;
  196. case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
  197. case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
  198. default:
  199. rfcomm_proto_list_parse_exit(ENOATTR);
  200. /* NOT REACHED */
  201. }
  202. /*
  203. * First protocol specific parameter for RFCOMM procotol must
  204. * be uint8 that represents RFCOMM channel number. So we must
  205. * have at least two bytes.
  206. */
  207. if (end - start < 2)
  208. rfcomm_proto_list_parse_exit(EINVAL);
  209. SDP_GET8(type, start);
  210. if (type != SDP_DATA_UINT8)
  211. rfcomm_proto_list_parse_exit(ENOATTR);
  212. SDP_GET8(*channel, start);
  213. rfcomm_proto_list_parse_exit(0);
  214. /* NOT REACHED */
  215. next_protocol:
  216. start += len;
  217. }
  218. /*
  219. * If we got here then it means we could not find RFCOMM protocol
  220. * descriptor, but the reply format was actually valid.
  221. */
  222. rfcomm_proto_list_parse_exit(ENOATTR);
  223. }