adapter.c

来自「LINUX下」· C语言 代码 · 共 2,715 行 · 第 1/5 页

C
2,715
字号
	limited = (new_mode == MODE_LIMITED ? TRUE : FALSE);	err = set_limited_discoverable(dd, adapter->dev.class, limited);	if (err < 0) {		hci_close_dev(dd);		return failed_strerror(msg, -err);	}	if (current_scan != scan_enable) {		struct hci_request rq;		uint8_t status = 0;		memset(&rq, 0, sizeof(rq));		rq.ogf    = OGF_HOST_CTL;		rq.ocf    = OCF_WRITE_SCAN_ENABLE;		rq.cparam = &scan_enable;		rq.clen   = sizeof(scan_enable);		rq.rparam = &status;		rq.rlen   = sizeof(status);		rq.event = EVT_CMD_COMPLETE;		if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) {			err = errno;			error("Sending write scan enable command failed: %s (%d)",					strerror(errno), errno);			hci_close_dev(dd);			return failed_strerror(msg, err);		}		if (status) {			error("Setting scan enable failed with status 0x%02x",					status);			hci_close_dev(dd);			return failed_strerror(msg, bt_error(status));		}	} else {		/* discoverable or limited */		if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) {			if (adapter->discov_timeout_id) {				g_source_remove(adapter->discov_timeout_id);				adapter->discov_timeout_id = 0;			}			if (!adapter->mode_sessions && !adapter->discov_timeout)				adapter_set_discov_timeout(adapter,						adapter->discov_timeout * 1000);		}	}done:	write_device_mode(&adapter->bdaddr, mode);	hci_close_dev(dd);	adapter->mode = new_mode;	return dbus_message_new_method_return(msg);}static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,				gboolean powered, void *data){	struct btd_adapter *adapter = data;	uint8_t mode;	mode = powered ? get_mode(&adapter->bdaddr, "on") : MODE_OFF;	if (mode == adapter->mode)		return dbus_message_new_method_return(msg);	return set_mode(conn, msg, mode, data);}static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg,				gboolean discoverable, void *data){	struct btd_adapter *adapter = data;	const char *strmode;	uint8_t mode;	strmode = discoverable ? "discoverable" : "connectable";	mode = get_mode(&adapter->bdaddr, strmode);	if (mode == adapter->mode)		return dbus_message_new_method_return(msg);	return set_mode(conn, msg, mode, data);}static struct session_req *find_session(GSList *list, DBusMessage *msg){	GSList *l;	const char *sender = dbus_message_get_sender(msg);	for (l = list; l; l = l->next) {		struct session_req *req = l->data;		const char *name = dbus_message_get_sender(req->msg);		if (g_str_equal(name, sender))			return req;	}	return NULL;}static void session_remove(struct session_req *req){	struct btd_adapter *adapter = req->adapter;	if (req->mode) {		GSList *l;		uint8_t mode = adapter->global_mode;		adapter->mode_sessions = g_slist_remove(adapter->mode_sessions,						req);		for (l = adapter->mode_sessions; l; l = l->next) {			struct session_req *req = l->data;			if (req->mode > mode)				mode = req->mode;		}		if (mode == adapter->mode)			return;		debug("Switching to '%s' mode", mode2str(mode));		set_mode(req->conn, req->msg, mode, adapter);	} else {		adapter->disc_sessions = g_slist_remove(adapter->disc_sessions,						req);		if (adapter->disc_sessions)			return;		debug("Stopping discovery", mode2str(adapter->global_mode));		if (adapter->state & STD_INQUIRY)			cancel_discovery(adapter);		else if (adapter->scheduler_id)			g_source_remove(adapter->scheduler_id);		else			cancel_periodic_discovery(adapter);	}}static void session_free(struct session_req *req){	const char *sender = dbus_message_get_sender(req->msg);	info("%s session %p with %s deactivated",		req->mode ? "Mode" : "Discovery", req, sender);	session_remove(req);	dbus_message_unref(req->msg);	dbus_connection_unref(req->conn);	g_free(req);}static struct session_req *session_ref(struct session_req *req){	req->refcount++;	debug("session_ref(%p): ref=%d", req, req->refcount);	return req;}static void session_unref(struct session_req *req){	req->refcount--;	debug("session_unref(%p): ref=%d", req, req->refcount);	if (req->refcount)		return;	if (req->id)		g_dbus_remove_watch(req->conn, req->id);	session_free(req);}static struct session_req *create_session(struct btd_adapter *adapter,					DBusConnection *conn, DBusMessage *msg,					uint8_t mode, GDBusWatchFunction cb){	struct session_req *req;	const char *sender = dbus_message_get_sender(msg);	req = g_new0(struct session_req, 1);	req->adapter = adapter;	req->conn = dbus_connection_ref(conn);	req->msg = dbus_message_ref(msg);	req->mode = mode;	if (cb)		req->id = g_dbus_add_disconnect_watch(conn,					dbus_message_get_sender(msg),					cb, req, NULL);	info("%s session %p with %s activated",		req->mode ? "Mode" : "Discovery", req, sender);	return session_ref(req);}static void confirm_mode_cb(struct agent *agent, DBusError *err, void *data){	struct session_req *req = data;	DBusMessage *reply;	if (err && dbus_error_is_set(err)) {		reply = dbus_message_new_error(req->msg, err->name, err->message);		dbus_connection_send(req->conn, reply, NULL);		dbus_message_unref(reply);		goto cleanup;	}	reply = set_mode(req->conn, req->msg, req->mode, req->adapter);	dbus_connection_send(req->conn, reply, NULL);	dbus_message_unref(reply);	if (!find_session(req->adapter->mode_sessions, req->msg))		goto cleanup;	return;cleanup:	session_unref(req);}static DBusMessage *confirm_mode(DBusConnection *conn, DBusMessage *msg,					const char *mode, void *data){	struct btd_adapter *adapter = data;	struct session_req *req;	int ret;	uint8_t umode;	if (!adapter->agent)		return dbus_message_new_method_return(msg);	umode = get_mode(&adapter->bdaddr, mode);	req = create_session(adapter, conn, msg, umode, NULL);	ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb,					req);	if (ret < 0) {		session_unref(req);		return invalid_args(msg);	}	return NULL;}static DBusMessage *set_discoverable_timeout(DBusConnection *conn,							DBusMessage *msg,							uint32_t timeout,							void *data){	struct btd_adapter *adapter = data;	const char *path;	if (adapter->discov_timeout == timeout && timeout == 0)		return dbus_message_new_method_return(msg);	if (adapter->discov_timeout_id) {		g_source_remove(adapter->discov_timeout_id);		adapter->discov_timeout_id = 0;	}	if ((timeout != 0) && (adapter->scan_mode & SCAN_INQUIRY))		adapter_set_discov_timeout(adapter, timeout * 1000);	adapter->discov_timeout = timeout;	write_discoverable_timeout(&adapter->bdaddr, timeout);	path = dbus_message_get_path(msg);	emit_property_changed(conn, path,				ADAPTER_INTERFACE, "DiscoverableTimeout",				DBUS_TYPE_UINT32, &timeout);	return dbus_message_new_method_return(msg);}static void update_ext_inquiry_response(int dd, struct hci_dev *dev){	uint8_t fec = 0, data[240];	if (!(dev->features[6] & LMP_EXT_INQ))		return;	memset(data, 0, sizeof(data));	if (dev->ssp_mode > 0)		create_ext_inquiry_response((char *) dev->name, data);	if (hci_write_ext_inquiry_response(dd, fec, data,						HCI_REQ_TIMEOUT) < 0)		error("Can't write extended inquiry response: %s (%d)",						strerror(errno), errno);}static int adapter_set_name(struct btd_adapter *adapter, const char *name){	struct hci_dev *dev = &adapter->dev;	int dd, err;	write_local_name(&adapter->bdaddr, (char *) name);	if (!adapter->up)		return 0;	dd = hci_open_dev(adapter->dev_id);	if (dd < 0) {		err = errno;		error("Can't open device hci%d: %s (%d)",					adapter->dev_id, strerror(err), err);		return -err;	}	if (hci_write_local_name(dd, name, HCI_REQ_TIMEOUT) < 0) {		err = errno;		error("Can't write name for hci%d: %s (%d)",					adapter->dev_id, strerror(err), err);		hci_close_dev(dd);		return -err;	}	strncpy((char *) dev->name, name, 248);	update_ext_inquiry_response(dd, dev);	hci_close_dev(dd);	return 0;}static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,					const char *name, void *data){	struct btd_adapter *adapter = data;	int ecode;	const char *path;	if (!g_utf8_validate(name, -1, NULL)) {		error("Name change failed: the supplied name isn't valid UTF-8");		return invalid_args(msg);	}	ecode = adapter_set_name(adapter, name);	if (ecode < 0)		return failed_strerror(msg, -ecode);	path = dbus_message_get_path(msg);	emit_property_changed(conn, path, ADAPTER_INTERFACE, "Name",				DBUS_TYPE_STRING, &name);	return dbus_message_new_method_return(msg);}static void reply_authentication_failure(struct bonding_request_info *bonding){	DBusMessage *reply;	int status;	status = bonding->hci_status ?			bonding->hci_status : HCI_AUTHENTICATION_FAILURE;	reply = new_authentication_return(bonding->msg, status);	if (reply) {		dbus_connection_send(bonding->conn, reply, NULL);		dbus_message_unref(reply);	}}struct btd_device *adapter_find_device(struct btd_adapter *adapter, const char *dest){	struct btd_device *device;	GSList *l;	if (!adapter)		return NULL;	l = g_slist_find_custom(adapter->devices,				dest, (GCompareFunc) device_address_cmp);	if (!l)		return NULL;	device = l->data;	return device;}struct btd_device *adapter_create_device(DBusConnection *conn,				struct btd_adapter *adapter, const char *address){	struct btd_device *device;	debug("adapter_create_device(%s)", address);	device = device_create(conn, adapter, address);	if (!device)		return NULL;	device_set_temporary(device, TRUE);	adapter->devices = g_slist_append(adapter->devices, device);	return device;}static DBusMessage *remove_bonding(DBusConnection *conn, DBusMessage *msg,					const char *address, void *data){	struct btd_adapter *adapter = data;	struct btd_device *device;	char filename[PATH_MAX + 1];	char *str, srcaddr[18];	bdaddr_t dst;	GSList *l;	int dev, err;	gboolean paired;	str2ba(address, &dst);	ba2str(&adapter->bdaddr, srcaddr);	dev = hci_open_dev(adapter->dev_id);	if (dev < 0 && msg)		return no_such_adapter(msg);	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr,			"linkkeys");	/* textfile_del doesn't return an error when the key is not found */	str = textfile_caseget(filename, address);	paired = str ? TRUE : FALSE;	g_free(str);	if (!paired && msg) {		hci_close_dev(dev);		return g_dbus_create_error(msg,				ERROR_INTERFACE ".DoesNotExist",				"Bonding does not exist");	}	/* Delete the link key from storage */	if (textfile_casedel(filename, address) < 0 && msg) {		hci_close_dev(dev);		err = errno;		return failed_strerror(msg, err);	}	/* Delete the link key from the Bluetooth chip */	hci_delete_stored_link_key(dev, &dst, 0, HCI_REQ_TIMEOUT);	/* find the connection */	l = g_slist_find_custom(adapter->active_conn, &dst,				active_conn_find_by_bdaddr);	if (l) {		struct active_conn_info *con = l->data;		/* Send the HCI disconnect command */		if ((hci_disconnect(dev, htobs(con->handle),					HCI_OE_USER_ENDED_CONNECTION,					HCI_REQ_TIMEOUT) < 0)					&& msg){			int err = errno;			error("Disconnect failed");			hci_close_dev(dev);			return failed_strerror(msg, err);		}	}	hci_close_dev(dev);	device = adapter_find_device(adapter, address);	if (!device)		goto proceed;	if (paired) {		gboolean paired = FALSE;		const gchar *dev_path = device_get_path(device);		emit_property_changed(conn, dev_path, DEVICE_INTERFACE,					"Paired", DBUS_TYPE_BOOLEAN, &paired);	}proceed:	if(!msg)		goto done;	return dbus_message_new_method_return(msg);done:	return NULL;}void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,				struct btd_device *device){	bdaddr_t dst;	const gchar *dev_path = device_get_path(device);	struct agent *agent;	char dstaddr[18];	device_get_address(device, &dst);	ba2str(&dst, dstaddr);	delete_entry(&adapter->bdaddr, "profiles", dstaddr);	adapter->devices = g_slist_remove(adapter->devices, device);	if (!device_is_temporary(device)) {		remove_bonding(conn, NULL, dstaddr, adapter);		g_dbus_emit_signal(conn, adapter->path,				ADAPTER_INTERFACE,				"DeviceRemoved",				DBUS_TYPE_OBJECT_PATH, &dev_path,				DBUS_TYPE_INVALID);		adapter_update_devices(adapter);	}	agent = device_get_agent(device);	if (agent) {		agent_destroy(agent, FALSE);		device_set_agent(device, NULL);	}	device_remove(conn, device);}struct btd_device *adapter_get_device(DBusConnection *conn,				struct btd_adapter *adapter, const gchar *address){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?