diff options
| -rw-r--r-- | hcid/dbus-adapter.c | 57 | ||||
| -rw-r--r-- | hcid/dbus.c | 120 | ||||
| -rw-r--r-- | hcid/dbus.h | 11 | ||||
| -rw-r--r-- | hcid/hcid.h | 2 | ||||
| -rw-r--r-- | hcid/security.c | 8 | 
5 files changed, 106 insertions, 92 deletions
| diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index 07583d77..749dad6f 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -1792,7 +1792,8 @@ static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBu  static DBusHandlerResult handle_dev_cancel_bonding_req(DBusConnection *conn, DBusMessage *msg, void *data)  {  	struct hci_dbus_data *dbus_data = data; -	struct slist *l; +	struct slist *la; +	DBusMessage *reply;  	DBusError err;  	bdaddr_t peer_bdaddr;  	const char *peer_addr; @@ -1830,11 +1831,11 @@ static DBusHandlerResult handle_dev_cancel_bonding_req(DBusConnection *conn, DBu  	if (dd < 0)  		return error_no_such_adapter(conn, msg); -	dbus_data->bonding->cancel = dbus_message_ref(msg); +	dbus_data->bonding->cancel = 1; -	l = slist_find(dbus_data->active_conn, &peer_bdaddr, active_conn_find_by_bdaddr); +	la = slist_find(dbus_data->active_conn, &peer_bdaddr, active_conn_find_by_bdaddr); -	if (!l) { +	if (!la) {  		/* connection request is pending */  		struct hci_request rq;  		create_conn_cancel_cp cp; @@ -1874,26 +1875,44 @@ static DBusHandlerResult handle_dev_cancel_bonding_req(DBusConnection *conn, DBu  		 */  	} else { -		struct active_conn_info *cinfo = l->data; - -		/* for unlock PIN Code Request */ -		hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &peer_bdaddr); +		struct slist *lb; +		struct active_conn_info *cinfo = la->data;  		/*  -		 * Disconnect from the remote device for safety, maybe the -		 * Controller already received the reply for PIN Code Request -		 */ -		if (dbus_data->bonding->disconnect) { -			if (hci_disconnect(dd, htobs(cinfo->handle), HCI_AUTHENTICATION_FAILURE, 1000) < 0) -				error("Disconnect failed"); +		 * It is already connected, search in the pending passkey requests to +		 * figure out the current stage(waiting host passkey/remote passkey) +		 */  +		lb = slist_find(dbus_data->pending_bondings, &peer_bdaddr, pending_bonding_cmp); +		if (lb) { +			struct pending_bonding_info *pb = lb->data; +			/* 0: waiting host passkey 1: waiting remote passkey */ +			if (pb->step) { +				if (dbus_data->bonding->disconnect) { + +					/* disconnect and let disconnect handler reply create bonding */ +					if (hci_disconnect(dd, htobs(cinfo->handle), HCI_AUTHENTICATION_FAILURE, 1000) < 0) +						error("Disconnect failed"); +				} else { +					/* +					 * If disconnect can't be applied and the PIN Code Request +					 * was already replied it doesn't make sense cancel the +					 * remote passkey: return not authorized. +					 */ + +					error_not_authorized(conn, msg); +					goto failed; +				} +			} else { + +				/* for unlock PIN Code Request */ +				hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &peer_bdaddr); +			}  		} - -		/* -		 * If disconnect can't be applied and the PIN Code Request -		 * was already replied let the Controller's timer to expire -		 */  	} +	reply = dbus_message_new_method_return(msg); +	send_reply_and_unref(conn, reply); +failed:  	hci_close_dev(dd);  	return DBUS_HANDLER_RESULT_HANDLED; diff --git a/hcid/dbus.c b/hcid/dbus.c index f356f6ba..fc778757 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -77,8 +77,6 @@ void bonding_request_free(struct bonding_request_info *dev )  	if (dev) {  		if (dev->rq)  			dbus_message_unref(dev->rq); -		if (dev->cancel) -			dbus_message_unref(dev->cancel);  		free(dev);  	}  } @@ -675,16 +673,19 @@ int hcid_dbus_stop_device(uint16_t id)  	return 0;  } -static int pending_bonding_cmp(const void *p1, const void *p2) +int pending_bonding_cmp(const void *p1, const void *p2)  { -	return p2 ? bacmp(p1, p2) : -1; +	const struct pending_bonding_info *pb1 = p1; +	const struct pending_bonding_info *pb2 = p2; + +	return p2 ? bacmp(&pb1->bdaddr, &pb2->bdaddr) : -1;  }  void hcid_dbus_pending_bonding_add(bdaddr_t *sba, bdaddr_t *dba)  {  	char path[MAX_PATH_LENGTH], addr[18];  	struct hci_dbus_data *pdata; -	bdaddr_t *peer; +	struct pending_bonding_info *peer;  	ba2str(sba, addr); @@ -695,8 +696,10 @@ void hcid_dbus_pending_bonding_add(bdaddr_t *sba, bdaddr_t *dba)  		return;  	} -	peer = malloc(sizeof(bdaddr_t)); -	bacpy(peer, dba); +	peer = malloc(sizeof(*peer)); +	memset(peer, 0, sizeof(*peer)); + +	bacpy(&peer->bdaddr, dba);  	pdata->pending_bondings = slist_append(pdata->pending_bondings, peer);  } @@ -796,14 +799,9 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u  	}  	if (pdata->bonding->cancel) { -		/* reply the cancel bonding */ -		message = dbus_message_new_method_return(pdata->bonding->cancel); -		send_reply_and_unref(connection, message); -  		/* reply authentication canceled */  		error_authentication_canceled(connection, pdata->bonding->rq);  	} else { -  		/* reply authentication success or an error */  		message = dbus_msg_new_authentication_return(pdata->bonding->rq, status);  		send_reply_and_unref(connection, message); @@ -820,51 +818,6 @@ failed:  	bt_free(peer_addr);  } -void hcid_dbus_create_conn_cancel(bdaddr_t *local, void *ptr) -{ -	typedef struct { -		uint8_t status; -		bdaddr_t bdaddr; -	}__attribute__ ((packed)) ret_param_conn_cancel; - -	char path[MAX_PATH_LENGTH]; -	bdaddr_t tmp; -	ret_param_conn_cancel *ret = ptr + sizeof(evt_cmd_complete); -	DBusMessage *reply; -	char *local_addr, *peer_addr; -	struct hci_dbus_data *pdata; -	int id; - -	baswap(&tmp, local); local_addr = batostr(&tmp); -	baswap(&tmp, &ret->bdaddr); peer_addr = batostr(&tmp); - -	id = hci_devid(local_addr); -	if (id < 0) { -		error("No matching device id for %s", local_addr); -		goto failed; -	} - -	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id); -	if (!dbus_connection_get_object_path_data(connection, path, (void *) &pdata)) { -		error("Getting %s path data failed!", path); -		goto failed; -	} - -	if (!pdata->bonding || !pdata->bonding->cancel || -			bacmp(&pdata->bonding->bdaddr, &ret->bdaddr)) -		goto failed; - -	if (!ret->status) { -		reply = dbus_message_new_method_return(pdata->bonding->cancel); -		send_reply_and_unref(connection, reply); -	} else -		error_failed(connection, pdata->bonding->cancel, bt_error(ret->status)); - -failed: -	bt_free(local_addr); -	bt_free(peer_addr); -} -  void hcid_dbus_inquiry_start(bdaddr_t *local)  {  	struct hci_dbus_data *pdata; @@ -1301,11 +1254,6 @@ void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, b  	}  	if (pdata->bonding->cancel) { -		/*  -		 * reply to cancel bonding was done in the cancel create connection -		 * handler or in the beginning if the controller doesn't support -		 * cancel cmd. Reply authentication canceled only. -		 */  		error_authentication_canceled(connection, pdata->bonding->rq);  		/* @@ -1426,14 +1374,9 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle  		send_reply_and_unref(connection, message);  #endif  		if (pdata->bonding->cancel) { -			/* reply the cancel bonding */ -			message = dbus_message_new_method_return(pdata->bonding->cancel); -			send_reply_and_unref(connection, message); -  			/* reply authentication canceled */  			error_authentication_canceled(connection, pdata->bonding->rq);  		} else { -  			message = dbus_msg_new_authentication_return(pdata->bonding->rq, HCI_AUTHENTICATION_FAILURE);  			send_reply_and_unref(connection, message);  		} @@ -2007,6 +1950,49 @@ failed:  	bt_free(local_addr);  } +void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr) +{ + +	typedef struct { +		uint8_t status; +		bdaddr_t bdaddr; +	} __attribute__ ((packed)) ret_pin_code_req_reply; + +	struct hci_dbus_data *pdata; +	char *local_addr; +	ret_pin_code_req_reply *ret = ptr + sizeof(evt_cmd_complete); +	struct slist *l; +	char path[MAX_PATH_LENGTH]; +	bdaddr_t tmp; +	int id; + +	baswap(&tmp, local); local_addr = batostr(&tmp); +	id = hci_devid(local_addr); +	if (id < 0) { +		error("No matching device id for %s", local_addr); +		goto failed; +	} + +	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id); + +	if (!dbus_connection_get_object_path_data(connection, path, (void *) &pdata)) { +		error("Getting %s path data failed!", path); +		goto failed; +	} + +	if (!pdata->pending_bondings) +		goto failed; + +	l = slist_find(pdata->pending_bondings, &ret->bdaddr, pending_bonding_cmp); +	if (l) { +		struct pending_bonding_info *p = l->data; +		p->step = 1; +	} + +failed: +	bt_free(local_addr); +} +  void create_bond_req_exit(const char *name, struct hci_dbus_data *pdata)  {  	char path[MAX_PATH_LENGTH]; diff --git a/hcid/dbus.h b/hcid/dbus.h index 0e0e95bb..90d7b325 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -86,10 +86,16 @@ struct discovered_dev_info {  struct bonding_request_info {  	bdaddr_t bdaddr;  	DBusMessage *rq; -	DBusMessage *cancel; +	int cancel;  	int disconnect; /* disconnect after finish */  }; +struct pending_bonding_info { +	bdaddr_t bdaddr; +	int step;   /* 0: waiting host passkey  1:waiting remote passkey */ + +}; +  struct active_conn_info {  	bdaddr_t bdaddr;  	uint16_t handle; @@ -109,7 +115,7 @@ struct hci_dbus_data {  	struct slist *passkey_agents;  	struct bonding_request_info *bonding;  	struct slist *active_conn; -	struct slist *pending_bondings; +	struct slist *pending_bondings;    /* track D-Bus and non D-Bus requests */  };  struct passkey_agent { @@ -214,6 +220,7 @@ static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusM  int active_conn_find_by_bdaddr(const void *data, const void *user_data);  void bonding_request_free(struct bonding_request_info *dev); +int pending_bonding_cmp(const void *p1, const void *p2);  int disc_device_append(struct slist **list, bdaddr_t *bdaddr, name_status_t name_status, int discover_type);  int disc_device_req_name(struct hci_dbus_data *dbus_data); diff --git a/hcid/hcid.h b/hcid/hcid.h index c7208222..7eb231f9 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -159,9 +159,9 @@ void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char  void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, bdaddr_t *peer);  void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, uint8_t reason);  void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status); -void hcid_dbus_create_conn_cancel(bdaddr_t *local, void *ptr);  void hcid_dbus_setname_complete(bdaddr_t *local);  void hcid_dbus_setscan_enable_complete(bdaddr_t *local); +void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr);  void init_devices(void);  int add_device(uint16_t dev_id); diff --git a/hcid/security.c b/hcid/security.c index 98c00ca8..b5eca651 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -431,15 +431,17 @@ static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr)  	case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):  		hcid_dbus_inquiry_complete(sba);  		break; -	case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL): -		hcid_dbus_create_conn_cancel(sba, ptr); -		break;  	case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):  		hcid_dbus_setname_complete(sba);  		break;  	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):  		hcid_dbus_setscan_enable_complete(sba);  		break; +	case cmd_opcode_pack(OGF_LINK_CTL, OCF_PIN_CODE_REPLY): +	case cmd_opcode_pack(OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY): +		hcid_dbus_pin_code_reply(sba, ptr); +		break; +  	};  } | 
