Add new Agent API : RequestPairingConsent.

This callback will be called for incoming pairing requests for 2.1
devices only when the remote IO capabilities are NoInputNoOutput
or DisplayOnly and the local IO capability is DisplayYesNo.
Currently, we were silently auto accepting.
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index 0c84e1c..c8ed7ab 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -74,6 +74,17 @@
 			Possible errors: org.bluez.Error.Rejected
 			                 org.bluez.Error.Canceled
 
+		void RequestPairingConsent(object device)
+
+			This method gets called when the service daemon
+			needs to confirm an incoming pairing request.
+
+			To accept it should return an empty reply
+			or an error to reject.
+
+			Possible errors: org.bluez.Error.Rejected
+			                 org.bluez.Error.Canceled
+
 		void Authorize(object device, string uuid)
 
 			This method gets called when the service daemon
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 9b1225c..49e7676 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -1083,6 +1083,7 @@
 	evt_user_confirm_request *req = ptr;
 	gboolean loc_mitm, rem_mitm;
 	struct bt_conn *conn;
+	struct agent *agent;
 
 	DBG("hci%d", index);
 
@@ -1102,6 +1103,19 @@
 		goto fail;
 	}
 
+	/* If local IO capabilities are DisplayYesNo and remote IO
+	 * capabiltiies are DisplayOnly or NoInputNoOutput;
+	 * call PairingConsent callback for incoming requests. */
+	if (conn->bonding_initiator == FALSE) {
+		if ((conn->loc_cap == 0x01) &&
+			(conn->rem_cap == 0x00 || conn->rem_cap == 0x03)) {
+			if (btd_event_user_consent(&dev->bdaddr, &req->bdaddr)
+					< 0)
+				goto fail;
+			return;
+		}
+	}
+
 	/* If no side requires MITM protection; auto-accept */
 	if ((conn->loc_auth == 0xff || !loc_mitm || conn->rem_cap == 0x03) &&
 					(!rem_mitm || conn->loc_cap == 0x03)) {
diff --git a/src/agent.c b/src/agent.c
index 40495bf..80eee95 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -53,7 +53,8 @@
 	AGENT_REQUEST_CONFIRMATION,
 	AGENT_REQUEST_PINCODE,
 	AGENT_REQUEST_AUTHORIZE,
-	AGENT_REQUEST_CONFIRM_MODE
+	AGENT_REQUEST_CONFIRM_MODE,
+	AGENT_REQUEST_PAIRING_CONSENT,
 } agent_request_type_t;
 
 struct agent {
@@ -694,6 +695,63 @@
 	return err;
 }
 
+static int pairing_consent_request_new(struct agent_request *req,
+						const char *device_path)
+{
+	struct agent *agent = req->agent;
+
+	req->msg = dbus_message_new_method_call(agent->name, agent->path,
+				"org.bluez.Agent", "RequestPairingConsent");
+	if (req->msg == NULL) {
+		error("Couldn't allocate D-Bus message");
+		return -ENOMEM;
+	}
+
+	dbus_message_append_args(req->msg,
+				DBUS_TYPE_OBJECT_PATH, &device_path,
+				DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(connection, req->msg,
+				&req->call, REQUEST_TIMEOUT) == FALSE) {
+		error("D-Bus send failed");
+		return -EIO;
+	}
+
+	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+
+	return 0;
+}
+
+int agent_request_pairing_consent(struct agent *agent, struct btd_device *device,
+				agent_cb cb, void *user_data,
+				GDestroyNotify destroy)
+{
+	struct agent_request *req;
+	const gchar *dev_path = device_get_path(device);
+	int err;
+
+	if (agent->request)
+		return -EBUSY;
+
+	DBG("Calling Agent.RequestPairingConsent: name=%s, path=%s",
+			agent->name, agent->path);
+
+	req = agent_request_new(agent, AGENT_REQUEST_PAIRING_CONSENT, cb,
+				user_data, destroy);
+
+	err = pairing_consent_request_new(req, dev_path);
+	if (err < 0)
+		goto failed;
+
+	agent->request = req;
+
+	return 0;
+
+failed:
+	agent_request_free(req, FALSE);
+	return err;
+}
+
 static int request_fallback(struct agent_request *req,
 				DBusPendingCallNotifyFunction function)
 {
diff --git a/src/agent.h b/src/agent.h
index e184250..aeb39df 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -61,6 +61,10 @@
 				uint32_t passkey, agent_cb cb,
 				void *user_data, GDestroyNotify destroy);
 
+int agent_request_pairing_consent(struct agent *agent,
+				struct btd_device *device, agent_cb cb,
+				void *user_data, GDestroyNotify destroy);
+
 int agent_display_passkey(struct agent *agent, struct btd_device *device,
 				uint32_t passkey);
 
diff --git a/src/device.c b/src/device.c
index 0d7a667..e7d7aa7 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2279,6 +2279,20 @@
 	device->authr->agent = NULL;
 }
 
+static void pairing_consent_cb(struct agent *agent, DBusError *err, void *data)
+{
+	struct authentication_req *auth = data;
+	struct btd_device *device = auth->device;
+
+	/* No need to reply anything if the authentication already failed */
+	if (!auth->cb)
+		return;
+
+	((agent_cb) auth->cb)(agent, err, device);
+
+	auth->cb = NULL;
+}
+
 int device_request_authentication(struct btd_device *device, auth_type_t type,
 						uint32_t passkey, void *cb)
 {
@@ -2324,6 +2338,13 @@
 	case AUTH_TYPE_NOTIFY:
 		err = agent_display_passkey(agent, device, passkey);
 		break;
+	case AUTH_TYPE_AUTO:
+		err = 0;
+		break;
+	case AUTH_TYPE_PAIRING_CONSENT:
+		err = agent_request_pairing_consent(agent, device,
+							pairing_consent_cb, auth, NULL);
+		break;
 	default:
 		err = -EINVAL;
 	}
@@ -2361,6 +2382,9 @@
 	case AUTH_TYPE_PASSKEY:
 		((agent_passkey_cb) auth->cb)(agent, &err, 0, device);
 		break;
+	case AUTH_TYPE_PAIRING_CONSENT:
+		((agent_cb) auth->cb) (agent, &err, device);
+		break;
 	case AUTH_TYPE_NOTIFY:
 		/* User Notify doesn't require any reply */
 		break;
diff --git a/src/device.h b/src/device.h
index ad7350a..17d9a3e 100644
--- a/src/device.h
+++ b/src/device.h
@@ -31,6 +31,8 @@
 	AUTH_TYPE_PASSKEY,
 	AUTH_TYPE_CONFIRM,
 	AUTH_TYPE_NOTIFY,
+	AUTH_TYPE_AUTO,
+	AUTH_TYPE_PAIRING_CONSENT,
 } auth_type_t;
 
 typedef enum {
diff --git a/src/event.c b/src/event.c
index 6be7ea2..7f3e357 100644
--- a/src/event.c
+++ b/src/event.c
@@ -219,6 +219,18 @@
 							passkey, confirm_cb);
 }
 
+int btd_event_user_consent(bdaddr_t *sba, bdaddr_t *dba)
+{
+	struct btd_adapter *adapter;
+	struct btd_device *device;
+
+	if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
+		return -ENODEV;
+
+	return device_request_authentication(device, AUTH_TYPE_PAIRING_CONSENT,
+						0, confirm_cb);
+}
+
 int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
 {
 	struct btd_adapter *adapter;