Add ability to disconnect from a device from the network server interface.

Change-Id: I40043877b9718a8c0287869a61f0a7b4620d5091
diff --git a/network/server.c b/network/server.c
index 652de14..975c7e7 100644
--- a/network/server.c
+++ b/network/server.c
@@ -125,6 +125,21 @@
 	return NULL;
 }
 
+static struct network_session *find_session_by_addr(GSList *list, bdaddr_t dst_addr)
+{
+	GSList *l;
+
+	for (l = list; l; l = l->next) {
+		struct network_session *session = l->data;
+
+		if (!bacmp(&session->dst, &dst_addr)) {
+			return session;
+		}
+	}
+
+	return NULL;
+}
+
 static void add_lang_attr(sdp_record_t *r)
 {
 	sdp_lang_attr_t base_lang;
@@ -276,6 +291,19 @@
 	return send(sk, &rsp, sizeof(rsp), 0);
 }
 
+static void session_free(void *data)
+{
+	struct network_session *session = data;
+
+	if (session->watch)
+		g_source_remove(session->watch);
+
+	if (session->io)
+		g_io_channel_unref(session->io);
+
+	g_free(session);
+}
+
 static void bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
 				gpointer data)
 {
@@ -296,6 +324,7 @@
 	g_io_channel_shutdown(chan, TRUE, NULL);
 	g_io_channel_unref(session->io);
 	session->io = NULL;
+	session_free(session);
 }
 
 
@@ -391,19 +420,6 @@
 	return 0;
 }
 
-static void session_free(void *data)
-{
-	struct network_session *session = data;
-
-	if (session->watch)
-		g_source_remove(session->watch);
-
-	if (session->io)
-		g_io_channel_unref(session->io);
-
-	g_free(session);
-}
-
 static void setup_destroy(void *user_data)
 {
 	struct network_adapter *na = user_data;
@@ -706,6 +722,39 @@
 	return reply;
 }
 
+static DBusMessage *disconnect_device(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	struct network_server *ns = data;
+	struct network_session *session;
+	const char *addr, *devname;
+	bdaddr_t dst_addr;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
+						DBUS_TYPE_STRING, &devname,
+						DBUS_TYPE_INVALID))
+		return NULL;
+
+	str2ba(addr, &dst_addr);
+	session = find_session_by_addr(ns->sessions, dst_addr);
+
+	if (!session)
+		return btd_error_failed(msg, "No active session");
+
+	if (session->io) {
+                bnep_if_down(devname);
+                bnep_kill_connection(&dst_addr);
+	} else
+		return btd_error_not_connected(msg);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
+	return reply;
+}
+
+
 static void adapter_free(struct network_adapter *na)
 {
 	if (na->io != NULL) {
@@ -760,6 +809,7 @@
 static GDBusMethodTable server_methods[] = {
 	{ "Register",	"ss",	"",	register_server		},
 	{ "Unregister",	"s",	"",	unregister_server	},
+	{ "DisconnectDevice", "ss",	"",	disconnect_device	},
 	{ }
 };