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 43static sdp_session_t open_session(void); 44static void build_ssp(sdp_data_t *, int, const char **); 45 46static 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 97int 98do_sdp_browse(int argc, const char **argv) 99{ 100 const char *av = ___STRING(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP); 101 102 if (argc > 1) 103 errx(EXIT_FAILURE, "Too many arguments"); 104 105 if (argc == 0) { 106 argc = 1; 107 argv = &av; 108 } 109 110 return do_sdp_search(argc, argv); 111} 112 113int 114do_sdp_record(int argc, const char **argv) 115{ 116 sdp_session_t ss; 117 sdp_data_t rsp; 118 char * ep; 119 unsigned long handle; 120 bool rv; 121 122 if (argc == 0) 123 errx(EXIT_FAILURE, "Record handle required"); 124 125 ss = open_session(); 126 127 for (; argc-- > 0; argv++) { 128 handle = strtoul(*argv, &ep, 0); 129 if (*argv[0] == '\0' || *ep != '\0' || handle > UINT32_MAX) 130 errx(EXIT_FAILURE, "Invalid handle: %s\n", *argv); 131 132 rv = sdp_service_attribute(ss, (uint32_t)handle, NULL, &rsp); 133 if (!rv) 134 warn("%s", *argv); 135 else 136 print_record(&rsp); 137 138 if (argc > 0) 139 printf("\n\n"); 140 } 141 142 sdp_close(ss); 143 return EXIT_SUCCESS; 144} 145 146int 147do_sdp_search(int argc, const char **argv) 148{ 149 sdp_session_t ss; 150 sdp_data_t ssp, rec, rsp; 151 bool rv; 152 153 if (argc < 1) 154 errx(EXIT_FAILURE, "UUID required"); 155 156 if (argc > 12) 157 errx(EXIT_FAILURE, "Too many UUIDs"); 158 159 build_ssp(&ssp, argc, argv); 160 161 ss = open_session(); 162 163 rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp); 164 if (!rv) 165 err(EXIT_FAILURE, "sdp_service_search_attribute"); 166 167 while (sdp_get_seq(&rsp, &rec)) { 168 if (!rv) 169 printf("\n\n"); 170 else 171 rv = false; 172 173 print_record(&rec); 174 } 175 176 if (rsp.next != rsp.end) { 177 printf("\n\nAdditional Data:\n"); 178 sdp_data_print(&rsp, 4); 179 } 180 181 sdp_close(ss); 182 183 return EXIT_SUCCESS; 184} 185 186static sdp_session_t 187open_session(void) 188{ 189 sdp_session_t ss; 190 191 if (bdaddr_any(&remote_addr)) 192 ss = sdp_open_local(control_socket); 193 else 194 ss = sdp_open(&local_addr, &remote_addr); 195 196 if (ss == NULL) 197 err(EXIT_FAILURE, "sdp_open"); 198 199 return ss; 200} 201 202/* 203 * build ServiceSearchPattern from arglist 204 */ 205static void 206build_ssp(sdp_data_t *ssp, int argc, const char **argv) 207{ 208 static uint8_t data[12 * sizeof(uuid_t)]; 209 char * ep; 210 uintmax_t umax; 211 uuid_t uuid; 212 uint32_t status; 213 int i; 214 215 ssp->next = data; 216 ssp->end = data + sizeof(data); 217 218 for (; argc-- > 0; argv++) { 219 uuid_from_string(*argv, &uuid, &status); 220 if (status != uuid_s_ok) { 221 umax = strtoumax(*argv, &ep, 0); 222 if (*argv[0] == '\0' || *ep != '\0') { 223 for (i = 0;; i++) { 224 if (i == __arraycount(aliases)) 225 errx(EXIT_FAILURE, 226 "%s: Bad UUID", *argv); 227 228 if (strcasecmp(aliases[i].name, 229 *argv) == 0) 230 break; 231 } 232 233 umax = aliases[i].uuid; 234 } else if (umax > UINT32_MAX) 235 errx(EXIT_FAILURE, "%s: Bad UUID", *argv); 236 237 uuid = BLUETOOTH_BASE_UUID; 238 uuid.time_low = (uint32_t)umax; 239 } 240 241 sdp_put_uuid(ssp, &uuid); 242 } 243 244 ssp->end = ssp->next; 245 ssp->next = data; 246} 247