1 /* $NetBSD: command.c,v 1.3 2009/12/05 16:54:13 plunky Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Iain Hibbert. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: command.c,v 1.3 2009/12/05 16:54:13 plunky Exp $"); 34 35 #include <bluetooth.h> 36 #include <err.h> 37 #include <sdp.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 #include "sdpquery.h" 42 43 static sdp_session_t open_session(void); 44 static void build_ssp(sdp_data_t *, int, const char **); 45 46 static struct alias { 47 uint16_t uuid; 48 const char * name; 49 const char * desc; 50 } aliases[] = { 51 { SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION, 52 "A2DP", "Advanced Audio Distribution Profile" }, 53 { SDP_UUID_PROTOCOL_BNEP, 54 "BNEP", "Bluetooth Network Encapsulation Protocol" }, 55 { SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS, 56 "CIP", "Common ISDN Access Service" }, 57 { SDP_SERVICE_CLASS_CORDLESS_TELEPHONY, 58 "CTP", "Cordless Telephony Service" }, 59 { SDP_SERVICE_CLASS_DIALUP_NETWORKING, 60 "DUN", "Dial Up Networking Service" }, 61 { SDP_SERVICE_CLASS_FAX, 62 "FAX", "Fax Service" }, 63 { SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER, 64 "FTRN", "File Transfer Service" }, 65 { SDP_SERVICE_CLASS_GN, 66 "GN", "Group ad-hoc Network Service" }, 67 { SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE, 68 "HID", "Human Interface Device Service" }, 69 { SDP_SERVICE_CLASS_HANDSFREE, 70 "HF", "Handsfree Service" }, 71 { SDP_SERVICE_CLASS_HEADSET, 72 "HSET", "Headset Service" }, 73 { SDP_UUID_PROTOCOL_L2CAP, 74 "L2CAP", "Logical Link Control and Adapatation Protocol" }, 75 { SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, 76 "LAN", "Lan access using PPP Service" }, 77 { SDP_SERVICE_CLASS_NAP, 78 "NAP", "Network Access Point Service" }, 79 { SDP_UUID_PROTOCOL_OBEX, 80 "OBEX", "Object Exchange Protocol" }, 81 { SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH, 82 "OPUSH", "Object Push Service" }, 83 { SDP_SERVICE_CLASS_PANU, 84 "PANU", "Personal Area Networking User Service" }, 85 { SDP_SERVICE_CLASS_PNP_INFORMATION, 86 "PNP", "PNP Information Service" }, 87 { SDP_UUID_PROTOCOL_RFCOMM, 88 "RFCOMM", "RFCOMM Protocol" }, 89 { SDP_UUID_PROTOCOL_SDP, 90 "SDP", "Service Discovery Protocol" }, 91 { SDP_SERVICE_CLASS_SERIAL_PORT, 92 "SP", "Serial Port Service" }, 93 { SDP_SERVICE_CLASS_IR_MC_SYNC, 94 "SYNC", "IrMC Sync Client Service" }, 95 }; 96 97 int 98 do_sdp_browse(int argc, const char **argv) 99 { 100 #define STR(x) __STRING(x) 101 const char *av = STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP); 102 #undef STR 103 104 if (argc > 1) 105 errx(EXIT_FAILURE, "Too many arguments"); 106 107 if (argc == 0) { 108 argc = 1; 109 argv = &av; 110 } 111 112 return do_sdp_search(argc, argv); 113 } 114 115 int 116 do_sdp_record(int argc, const char **argv) 117 { 118 sdp_session_t ss; 119 sdp_data_t rsp; 120 char * ep; 121 unsigned long handle; 122 bool rv; 123 124 if (argc == 0) 125 errx(EXIT_FAILURE, "Record handle required"); 126 127 ss = open_session(); 128 129 for (; argc-- > 0; argv++) { 130 handle = strtoul(*argv, &ep, 0); 131 if (*argv[0] == '\0' || *ep != '\0' || handle > UINT32_MAX) 132 errx(EXIT_FAILURE, "Invalid handle: %s\n", *argv); 133 134 rv = sdp_service_attribute(ss, (uint32_t)handle, NULL, &rsp); 135 if (!rv) 136 warn("%s", *argv); 137 else 138 print_record(&rsp); 139 140 if (argc > 0) 141 printf("\n\n"); 142 } 143 144 sdp_close(ss); 145 return EXIT_SUCCESS; 146 } 147 148 int 149 do_sdp_search(int argc, const char **argv) 150 { 151 sdp_session_t ss; 152 sdp_data_t ssp, rec, rsp; 153 bool rv; 154 155 if (argc < 1) 156 errx(EXIT_FAILURE, "UUID required"); 157 158 if (argc > 12) 159 errx(EXIT_FAILURE, "Too many UUIDs"); 160 161 build_ssp(&ssp, argc, argv); 162 163 ss = open_session(); 164 165 rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp); 166 if (!rv) 167 err(EXIT_FAILURE, "sdp_service_search_attribute"); 168 169 while (sdp_get_seq(&rsp, &rec)) { 170 if (!rv) 171 printf("\n\n"); 172 else 173 rv = false; 174 175 print_record(&rec); 176 } 177 178 if (rsp.next != rsp.end) { 179 printf("\n\nAdditional Data:\n"); 180 sdp_data_print(&rsp, 4); 181 } 182 183 sdp_close(ss); 184 185 return EXIT_SUCCESS; 186 } 187 188 static sdp_session_t 189 open_session(void) 190 { 191 sdp_session_t ss; 192 193 if (bdaddr_any(&remote_addr)) 194 ss = sdp_open_local(control_socket); 195 else 196 ss = sdp_open(&local_addr, &remote_addr); 197 198 if (ss == NULL) 199 err(EXIT_FAILURE, "sdp_open"); 200 201 return ss; 202 } 203 204 /* 205 * build ServiceSearchPattern from arglist 206 */ 207 static void 208 build_ssp(sdp_data_t *ssp, int argc, const char **argv) 209 { 210 static uint8_t data[12 * sizeof(uuid_t)]; 211 char * ep; 212 uintmax_t umax; 213 uuid_t uuid; 214 uint32_t status; 215 int i; 216 217 ssp->next = data; 218 ssp->end = data + sizeof(data); 219 220 for (; argc-- > 0; argv++) { 221 uuid_from_string(*argv, &uuid, &status); 222 if (status != uuid_s_ok) { 223 umax = strtoumax(*argv, &ep, 0); 224 if (*argv[0] == '\0' || *ep != '\0') { 225 for (i = 0;; i++) { 226 if (i == __arraycount(aliases)) 227 errx(EXIT_FAILURE, 228 "%s: Bad UUID", *argv); 229 230 if (strcasecmp(aliases[i].name, 231 *argv) == 0) 232 break; 233 } 234 235 umax = aliases[i].uuid; 236 } else if (umax > UINT32_MAX) 237 errx(EXIT_FAILURE, "%s: Bad UUID", *argv); 238 239 uuid = BLUETOOTH_BASE_UUID; 240 uuid.time_low = (uint32_t)umax; 241 } 242 243 sdp_put_uuid(ssp, &uuid); 244 } 245 246 ssp->end = ssp->next; 247 ssp->next = data; 248 } 249