示例#1
0
static int
bt_query(struct l2cap_info *info, uint16_t service_class)
{
	sdp_attr_t values[BT_NUM_VALUES];
	uint8_t buffer[BT_NUM_VALUES][BT_BUF_SIZE];
	void *ss;
	int psm = -1;
	int n;

	memset(buffer, 0, sizeof(buffer));
	memset(values, 0, sizeof(values));

	ss = sdp_open(&info->laddr, &info->raddr);
	if (ss == NULL || sdp_error(ss) != 0) {
		DPRINTF("Could not open SDP\n");
		return (psm);
	}
	/* Initialize attribute values array */
	for (n = 0; n != BT_NUM_VALUES; n++) {
		values[n].flags = SDP_ATTR_INVALID;
		values[n].vlen = BT_BUF_SIZE;
		values[n].value = buffer[n];
	}

	/* Do SDP Service Search Attribute Request */
	n = sdp_search(ss, 1, &service_class, 1, bt_attrs, BT_NUM_VALUES, values);
	if (n != 0) {
		DPRINTF("SDP search failed\n");
		goto done;
	}
	/* Print attributes values */
	for (n = 0; n != BT_NUM_VALUES; n++) {
		if (values[n].flags != SDP_ATTR_OK)
			break;
		if (values[n].attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST)
			continue;
		psm = bt_find_psm(values[n].value, values[n].value + values[n].vlen);
		if (psm > -1)
			break;
	}
done:
	sdp_close(ss);
	return (psm);
}
示例#2
0
/* Perform SDP search command */
static int
do_sdp_search(void *xs, int argc, char **argv)
{
	char		*ep = NULL;
	int32_t		 n, type, value;
	uint16_t	 service;

	/* Parse command line arguments */
	switch (argc) {
	case 1:
		n = strtoul(argv[0], &ep, 16);
		if (*ep != 0) {
			switch (tolower(argv[0][0])) {
			case 'c': /* CIP/CTP */
				switch (tolower(argv[0][1])) {
				case 'i':
					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
					break;

				case 't':
					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
					break;

				default:
					return (USAGE);
					/* NOT REACHED */
				}
				break;

			case 'd': /* DialUp Networking */
				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
				break;

			case 'f': /* Fax/OBEX File Transfer */
				switch (tolower(argv[0][1])) {
				case 'a':
					service = SDP_SERVICE_CLASS_FAX;
					break;

				case 't':
					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
					break;

				default:
					return (USAGE);
					/* NOT REACHED */
				}
				break;

			case 'g': /* GN */
				service = SDP_SERVICE_CLASS_GN;
				break;

			case 'h': /* Headset/HID */
				switch (tolower(argv[0][1])) {
				case 'i':
					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
					break;

				case 's':
					service = SDP_SERVICE_CLASS_HEADSET;
					break;

				default:
					return (USAGE);
					/* NOT REACHED */
				}
				break;

			case 'l': /* LAN Access Using PPP */
				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
				break;

			case 'n': /* NAP */
				service = SDP_SERVICE_CLASS_NAP;
				break;

			case 'o': /* OBEX Object Push */
				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
				break;

			case 's': /* Serial Port */
				service = SDP_SERVICE_CLASS_SERIAL_PORT;
				break;

			default:
				return (USAGE);
				/* NOT REACHED */
			}
		} else
			service = (uint16_t) n;
		break;

	default:
		return (USAGE);
	}

	/* Initialize attribute values array */
	for (n = 0; n < values_len; n ++) {
		values[n].flags = SDP_ATTR_INVALID;
		values[n].attr = 0;
		values[n].vlen = BSIZE;
		values[n].value = buffer[n];
	}

	/* Do SDP Service Search Attribute Request */
	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
	if (n != 0)
		return (ERROR);

	/* Print attributes values */
	for (n = 0; n < values_len; n ++) {
		if (values[n].flags != SDP_ATTR_OK)
			break;

		switch (values[n].attr) {
		case SDP_ATTR_SERVICE_RECORD_HANDLE:
			fprintf(stdout, "\n");
			if (values[n].vlen == 5) {
				SDP_GET8(type, values[n].value);
				if (type == SDP_DATA_UINT32) {
					SDP_GET32(value, values[n].value);
					fprintf(stdout, "Record Handle: " \
							"%#8.8x\n", value);
				} else
					fprintf(stderr, "Invalid type=%#x " \
							"Record Handle " \
							"attribute!\n", type);
			} else
				fprintf(stderr, "Invalid size=%d for Record " \
						"Handle attribute\n",
						values[n].vlen);
			break;

		case SDP_ATTR_SERVICE_CLASS_ID_LIST:
			fprintf(stdout, "Service Class ID List:\n");
			print_service_class_id_list(values[n].value,
					values[n].value + values[n].vlen);
			break;

		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
			fprintf(stdout, "Protocol Descriptor List:\n");
			print_protocol_descriptor_list(values[n].value,
					values[n].value + values[n].vlen);
			break;

		case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
			fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
			print_bluetooth_profile_descriptor_list(values[n].value,
					values[n].value + values[n].vlen);
			break;

		default:
			fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
					values[n].attr);
			break;
		}
	}

	return (OK);
} /* do_sdp_search */
示例#3
0
static int find_service_channel(bdaddr_t *adapter, bdaddr_t *device, int only_gnapplet, uint16_t svclass_id)
{
	int i, channel = -1;
	char name[64];
	void *ss = NULL;
	uint32_t attrs[] = {
		SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
			SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
		SDP_ATTR_RANGE( SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
			SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET),
	};
	/* Buffer for the attributes */
	static uint8_t          buffer[NRECS * attrs_len][BSIZE];
	/* SDP attributes */
	static sdp_attr_t       values[NRECS * attrs_len];

	/* Initialize attribute values array */
	for (i = 0; i < values_len; i ++) {
		values[i].flags = SDP_ATTR_INVALID;
		values[i].attr = 0;
		values[i].vlen = BSIZE;
		values[i].value = buffer[i];
	}

	if ((ss = sdp_open(adapter, device)) == NULL)
		return -1;

	if (sdp_error(ss) != 0)
		goto end;

	if (sdp_search(ss, 1, &svclass_id, attrs_len, attrs, values_len, values) != 0)
		goto end;

	for (i = 0; i < values_len; i++) {
		union {
			uint8_t		uint8;
			uint16_t	uint16;
			uint32_t	uint32;
			uint64_t	uint64;
			int128_t	int128;
		} value;
		uint8_t *start, *end;
		uint32_t type, len;

		if (values[i].flags != SDP_ATTR_OK)
			break;

		start = values[i].value;
		end = values[i].value + values[i].vlen;

		switch (values[i].attr) {
		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
			SDP_GET8(type, start);
			switch (type) {
			case SDP_DATA_SEQ8:
				SDP_GET8(len, start);
				break;

			case SDP_DATA_SEQ16:
				SDP_GET16(len, start);
				break;

			case SDP_DATA_SEQ32:
				SDP_GET32(len, start);
				break;

			default:
				goto end;
				break;
			}

			SDP_GET8(type, start);
			switch (type) {
			case SDP_DATA_SEQ8:
				SDP_GET8(len, start);
				break;

			case SDP_DATA_SEQ16:
				SDP_GET16(len, start);
				break;

			case SDP_DATA_SEQ32:
				SDP_GET32(len, start);
				break;

			default:
				goto end;
			}

			while (start < end) {
				SDP_GET8(type, start);
				switch (type) {
				case SDP_DATA_UUID16:
					SDP_GET16(value.uint16, start);
					break;

				case SDP_DATA_UUID32:
					SDP_GET32(value.uint32, start);
					break;

				case SDP_DATA_UUID128:
					SDP_GET_UUID128(&value.int128, start);
					break;

				default:
					goto end;
				}
				if (value.uint16 == 3) {
					SDP_GET8(type, start);
					switch (type) {
					case SDP_DATA_UINT8:
					case SDP_DATA_INT8:
						SDP_GET8(value.uint8, start);
						channel = value.uint8;
						break;

					case SDP_DATA_UINT16:
					case SDP_DATA_INT16:
						SDP_GET16(value.uint16, start);
						channel = value.uint16;
						break;

					case SDP_DATA_UINT32:
					case SDP_DATA_INT32:
						SDP_GET32(value.uint32, start);
						channel = value.uint32;
						break;

					default:
						goto end;
					}
				} else {
					SDP_GET8(type, start);
					switch (type) {
					case SDP_DATA_SEQ8:
					case SDP_DATA_UINT8:
					case SDP_DATA_INT8:
					case SDP_DATA_BOOL:
						SDP_GET8(value.uint8, start);
						break;

					case SDP_DATA_SEQ16:
					case SDP_DATA_UINT16:
					case SDP_DATA_INT16:
					case SDP_DATA_UUID16:
						SDP_GET16(value.uint16, start);
						break;

					case SDP_DATA_SEQ32:
					case SDP_DATA_UINT32:
					case SDP_DATA_INT32:
					case SDP_DATA_UUID32:
						SDP_GET32(value.uint32, start);
						break;

					case SDP_DATA_UINT64:
					case SDP_DATA_INT64:
						SDP_GET64(value.uint64, start);
						break;

					case SDP_DATA_UINT128:
					case SDP_DATA_INT128:
						SDP_GET128(&value.int128, start);
						break;

					default:
						goto end;
					}
				}
			}
			start += len;
			break;

		case SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET:
			if (channel == -1)
				break;
			
			SDP_GET8(type, start);
			switch (type) {
				case SDP_DATA_STR8:
				case SDP_DATA_URL8:
					SDP_GET8(len, start);
					snprintf(name, sizeof(name), "%*.*s", len, len, (char *) start);
					start += len;
					break;

				case SDP_DATA_STR16:
				case SDP_DATA_URL16:
					SDP_GET16(len, start);
					snprintf(name, sizeof(name), "%*.*s", len, len, (char *) start);
					start += len;
					break;

				case SDP_DATA_STR32:
				case SDP_DATA_URL32:
					SDP_GET32(len, start);
					snprintf(name, sizeof(name), "%*.*s", len, len, (char *) start);
					start += len;
					break;

				default:
					goto end;
			}
			if (name == NULL)
				break;

			if (only_gnapplet != 0) {
				if (strcmp(name, "gnapplet") == 0)
					goto end;
				else {
					channel = -1;
					break;
				}
			}
			
			if (strstr(name, "Nokia PC Suite") != NULL) {
				channel = -1;
				break;
			}

			if (strstr(name, "Bluetooth Serial Port") != NULL) {
				channel = -1;
				break;
			}

			if (strstr(name, "m-Router Connectivity") != NULL) {
				channel = -1;
				break;
			}

			goto end;
		}
	}

end:
	sdp_close(ss);
	return channel;
}
示例#4
0
static void
client_query(void)
{
	uint8_t buffer[512];
	sdp_attr_t attr;
	uint32_t range;
	void *ss;
	int rv;
	uint8_t *seq0, *seq1;

	attr.flags = SDP_ATTR_INVALID;
	attr.attr = 0;
	attr.vlen = sizeof(buffer);
	attr.value = buffer;

	range = SDP_ATTR_RANGE(SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
			       SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);

	ss = sdp_open(&local_bdaddr, &remote_bdaddr);
	if (ss == NULL || (errno = sdp_error(ss)) != 0) {
		log_err("%s: %m", service_name);
		exit(EXIT_FAILURE);
	}

	log_info("Searching for %s service at %s",
	    service_name, bt_ntoa(&remote_bdaddr, NULL));

	rv = sdp_search(ss, 1, &service_class, 1, &range, 1, &attr);
	if (rv != 0) {
		log_err("%s: %s", service_name, strerror(sdp_error(ss)));
		exit(EXIT_FAILURE);
	}

	sdp_close(ss);

	if (attr.flags != SDP_ATTR_OK
	    || attr.attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) {
		log_err("%s service not found", service_name);
		exit(EXIT_FAILURE);
	}

	/*
	 * we expect the following protocol descriptor list
	 *
	 *	seq len
	 *	  seq len
	 *	    uuid value == L2CAP
	 *	    uint16 value16 => PSM
	 *	  seq len
	 *	    uuid value == BNEP
	 */
	if (_sdp_get_seq(&attr.value, attr.value + attr.vlen, &seq0)
	    && _sdp_get_seq(&seq0, attr.value, &seq1)
	    && _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_L2CAP)
	    && _sdp_get_uint16(&seq1, seq0, &l2cap_psm)
	    && _sdp_get_seq(&seq0, attr.value, &seq1)
	    && _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_BNEP)) {
		log_info("Found PSM %d for service %s", l2cap_psm, service_name);
		return;
	}

	log_err("%s query failed", service_name);
	exit(EXIT_FAILURE);
}
示例#5
0
int
rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
			int service, int *channel, int *error)
{
	uint8_t		 buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE];
	void		*ss    = NULL;
	uint16_t	 serv  = (uint16_t) service;
	uint32_t	 attr  = SDP_ATTR_RANGE(
					SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
					SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
	sdp_attr_t	 proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
	uint32_t	 type, len;

	if (local == NULL)
		local = NG_HCI_BDADDR_ANY;
	if (remote == NULL || channel == NULL)
		rfcomm_channel_lookup_exit(EINVAL);

	if ((ss = sdp_open(local, remote)) == NULL)
		rfcomm_channel_lookup_exit(ENOMEM);
	if (sdp_error(ss) != 0)
		rfcomm_channel_lookup_exit(sdp_error(ss));

	if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
		rfcomm_channel_lookup_exit(sdp_error(ss));
	if (proto.flags != SDP_ATTR_OK)
		rfcomm_channel_lookup_exit(ENOATTR);

	sdp_close(ss);
	ss = NULL;

	/*
	 * If it is possible for more than one kind of protocol stack to be 
	 * used to gain access to the service, the ProtocolDescriptorList
	 * takes the form of a data element alternative. We always use the
	 * first protocol stack.
	 *
	 * A minimal Protocol Descriptor List for RFCOMM based service would
	 * look like
	 *
	 * seq8 len8			- 2 bytes
	 *	seq8 len8		- 2 bytes
	 *		uuid16 value16	- 3 bytes	L2CAP
	 *	seq8 len8		- 2 bytes
	 *		uuid16 value16	- 3 bytes	RFCOMM
	 *		uint8  value8	- 2 bytes	RFCOMM param #1 
	 *				=========
	 *				 14 bytes
	 *
	 * Lets not count first [seq8 len8] wrapper, so the minimal size of 
	 * the Protocol Descriptor List (the data we are actually interested
	 * in) for RFCOMM based service would be 12 bytes.
	 */

	if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
		rfcomm_channel_lookup_exit(EINVAL);

	SDP_GET8(type, proto.value);

	if (type == SDP_DATA_ALT8) {
		SDP_GET8(len, proto.value);
	} else if (type == SDP_DATA_ALT16) {
		SDP_GET16(len, proto.value);
	} else if (type == SDP_DATA_ALT32) {
		SDP_GET32(len, proto.value);
	} else
		len = 0;

	if (len > 0)
		SDP_GET8(type, proto.value);

	switch (type) {
	case SDP_DATA_SEQ8:
		SDP_GET8(len, proto.value);
		break;

	case SDP_DATA_SEQ16:
		SDP_GET16(len, proto.value);
		break;

	case SDP_DATA_SEQ32:
		SDP_GET32(len, proto.value);
		break;

	default:
		rfcomm_channel_lookup_exit(ENOATTR);
		/* NOT REACHED */
	}

	if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
		rfcomm_channel_lookup_exit(EINVAL);

	return (rfcomm_proto_list_parse(proto.value,
					buffer + proto.vlen, channel, error));
}
示例#6
0
文件: sdp.c 项目: hmatyschok/MeshBSD
static int32_t
hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error)
{
	void	*ss = NULL;
	uint8_t	*hid_descriptor = NULL;
	int32_t	 i, control_psm = -1, interrupt_psm = -1,
		 reconnect_initiate = -1,
		 normally_connectable = 0, battery_power = 0,
		 hid_descriptor_length = -1;

	if (local == NULL)
		local = NG_HCI_BDADDR_ANY;
	if (hd == NULL)
		hid_sdp_query_exit(EINVAL);

	for (i = 0; i < nvalues; i ++) {
		values[i].flags = SDP_ATTR_INVALID;
		values[i].attr = 0;
		values[i].vlen = sizeof(buffer[i]);
		values[i].value = buffer[i];
	}

	if ((ss = sdp_open(local, &hd->bdaddr)) == NULL)
		hid_sdp_query_exit(ENOMEM);
	if (sdp_error(ss) != 0)
		hid_sdp_query_exit(sdp_error(ss));
	if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0)
                hid_sdp_query_exit(sdp_error(ss));

        sdp_close(ss);
        ss = NULL;

	for (i = 0; i < nvalues; i ++) {
		if (values[i].flags != SDP_ATTR_OK)
			continue;

		switch (values[i].attr) {
		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
			control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
			break;

		case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
			interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
			break;

		case 0x0205: /* HIDReconnectInitiate */
			reconnect_initiate = hid_sdp_parse_boolean(&values[i]);
			break;

		case 0x0206: /* HIDDescriptorList */
			if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) {
				hid_descriptor = values[i].value;
				hid_descriptor_length = values[i].vlen;
			}
			break;

		case 0x0209: /* HIDBatteryPower */
			battery_power = hid_sdp_parse_boolean(&values[i]);
			break;

		case 0x020d: /* HIDNormallyConnectable */
			normally_connectable = hid_sdp_parse_boolean(&values[i]);
			break;
		}
	}

	if (control_psm == -1 || interrupt_psm == -1 ||
	    reconnect_initiate == -1 ||
	    hid_descriptor == NULL || hid_descriptor_length == -1)
		hid_sdp_query_exit(ENOATTR);

	hd->control_psm = control_psm;
	hd->interrupt_psm = interrupt_psm;
	hd->reconnect_initiate = reconnect_initiate? 1 : 0;
	hd->battery_power = battery_power? 1 : 0;
	hd->normally_connectable = normally_connectable? 1 : 0;
	hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length);
	if (hd->desc == NULL)
		hid_sdp_query_exit(ENOMEM);

	return (0);
}