Home | History | Annotate | Line # | Download | only in sdpquery
      1 /*	$NetBSD: command.c,v 1.6 2023/12/17 14:38:49 andvar 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.6 2023/12/17 14:38:49 andvar 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 Adaptation 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 	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 
    113 int
    114 do_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", *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 
    146 int
    147 do_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 
    186 static sdp_session_t
    187 open_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  */
    205 static void
    206 build_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