From 9a751bbca1af53e6395f1b676560a5d5353ee33f Mon Sep 17 00:00:00 2001
From: Alexandre Bailon <abailon@baylibre.com>
Date: Tue, 7 Mar 2017 21:38:02 +0100
Subject: [PATCH] netlink: Update netlink to become a controller

Currently, netlink is mandatory and uses some specifics API.
In order to make gbridge more scalable and generic, update netlink
to register a controller.

Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
---
 Makefile.am                           |  5 ++-
 configure.ac                          | 10 ++++++
 controller.c                          |  9 +++--
 controller.h                          |  1 +
 netlink.c => controllers/gb_netlink.c | 49 +++++++++++++++++++++------
 netlink.h => controllers/netlink.h    |  0
 greybus.c                             |  5 ++-
 main.c                                | 38 +++++----------------
 8 files changed, 70 insertions(+), 47 deletions(-)
 rename netlink.c => controllers/gb_netlink.c (83%)
 rename netlink.h => controllers/netlink.h (100%)

diff --git a/Makefile.am b/Makefile.am
index f6daea9..66e3083 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,12 +5,15 @@ gbridge_CFLAGS += `pkg-config --cflags libnl-3.0 libnl-genl-3.0`
 gbridge_CFLAGS += `pkg-config --cflags bluez`
 
 gbridge_SOURCES = main.c \
-		  netlink.c \
 		  debug.c \
 		  greybus.c \
 		  controller.c \
 		  protocols/svc.c
 
+if NETLINK
+gbridge_SOURCES += controllers/gb_netlink.c
+endif
+
 if TPCIP
 gbridge_SOURCES += controllers/tcpip.c
 endif
diff --git a/configure.ac b/configure.ac
index 3f95c11..a1c509e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,6 +53,16 @@ AC_ARG_ENABLE([uart],
 esac])
 AM_CONDITIONAL([UART], [test x$uart = xtrue])
 
+AC_ARG_ENABLE([netlink],
+[  --enable-netlink    Enable Netlink],
+[case "${enableval}" in
+	yes) netlink=true ;
+	     AC_DEFINE([NETLINK], [1], ["Netlink support"]) ;;
+	no)  netlink=false ;;
+	*) AC_MSG_ERROR([bad value ${enableval} for --enable-netlink]) ;;
+esac])
+AM_CONDITIONAL([NETLINK], [test x$netlink = xtrue])
+
 AC_ARG_VAR([GBDIR], ["greybus sources directory"])
 AS_IF([test "$GBDIR" = ""], [
   AC_MSG_ERROR([Environment variable GBDIR needs to be set])
diff --git a/controller.c b/controller.c
index ff75668..24a8ed2 100644
--- a/controller.c
+++ b/controller.c
@@ -22,7 +22,6 @@
 
 #include <debug.h>
 #include <gbridge.h>
-#include <netlink.h>
 #include <controller.h>
 
 static
@@ -164,7 +163,7 @@ static void *interface_recv(void *data)
 			continue;
 		}
 
-		ret = netlink_send(conn->cport1_id, buffer, ret);
+		ret = controller_write(AP_INTF_ID, conn->cport1_id, buffer, ret);
 		if (ret < 0) {
 			pr_err("Failed to transmit data\n");
 		}
@@ -299,7 +298,8 @@ void *connection_recv(void *data)
 
 		pr_dump(buffer, ret);
 
-		ret = netlink_send(conn->cport1_id, buffer, ret);
+		ret = controller_write(conn->intf1->id, conn->cport1_id,
+				       buffer, ret);
 		if (ret < 0) {
 			pr_err("Failed to transmit data\n");
 		}
@@ -391,6 +391,9 @@ void register_controller(struct controller *controller)
 
 static void register_controllers(void)
 {
+#ifdef NETLINK
+	register_controller(&netlink_controller);
+#endif
 #ifdef HAVE_LIBBLUETOOTH
 	register_controller(&bluetooth_controller);
 #endif
diff --git a/controller.h b/controller.h
index 14748c5..1c1f58f 100644
--- a/controller.h
+++ b/controller.h
@@ -80,6 +80,7 @@ struct controller {
 
 extern struct controller bluetooth_controller;
 extern struct controller tcpip_controller;
+extern struct controller netlink_controller;
 
 void cport_pack(struct gb_operation_msg_hdr *header, uint16_t cport_id);
 uint16_t cport_unpack(struct gb_operation_msg_hdr *header);
diff --git a/netlink.c b/controllers/gb_netlink.c
similarity index 83%
rename from netlink.c
rename to controllers/gb_netlink.c
index f8ae29c..c67de45 100644
--- a/netlink.c
+++ b/controllers/gb_netlink.c
@@ -91,7 +91,7 @@ static struct genl_ops ops = {
 	.o_ncmds = ARRAY_SIZE(cmds),
 };
 
-int netlink_send(uint16_t hd_cport_id, void *data, size_t len)
+int netlink_write(struct connection *conn, void *data, size_t len)
 {
 	struct nl_data *nl_data;
 	struct nl_msg *msg;
@@ -120,7 +120,7 @@ int netlink_send(uint16_t hd_cport_id, void *data, size_t len)
 		goto err_msg_free;
 	}
 
-	nla_put_u32(msg, GB_NL_A_CPORT, hd_cport_id);
+	nla_put_u32(msg, GB_NL_A_CPORT, conn->cport1_id);
 	nla_put_data(msg, GB_NL_A_DATA, nl_data);
 	ret = nl_send_auto(sock, msg);
 	if (ret < 0)
@@ -172,6 +172,27 @@ static int netlink_hd_reset(void)
 void *nl_recv_cb(void *data)
 {
 	int ret;
+	struct controller *ctrl = data;
+
+	if (!interface_create(ctrl, 0, 0, 0, NULL)) {
+		pr_err("Failed to create AP interface\n");
+		return NULL;
+	}
+
+	ret = svc_register_driver();
+	if (ret) {
+		pr_err("Failed to register SVC\n");
+		return NULL;
+	}
+
+	/* HACK: create a connection for SVC */
+	connection_create(0, 0, 0, 0);
+
+	ret = svc_init();
+	if (ret) {
+		pr_err("Failed to init SVC\n");
+		return NULL;
+	}
 
 	while (1) {
 		ret = nl_recvmsgs_default(sock);
@@ -189,7 +210,7 @@ int events_cb(struct nl_msg *msg, void *arg)
 	return genl_handle_msg(msg, arg);
 }
 
-int netlink_init(void)
+int netlink_init(struct controller * ctrl)
 {
 	int ret;
 
@@ -212,7 +233,7 @@ int netlink_init(void)
 		goto error;
 	}
 
-	return pthread_create(&nl_recv_thread, NULL, nl_recv_cb, NULL);
+	return pthread_create(&nl_recv_thread, NULL, nl_recv_cb, ctrl);
 
  error:
 	nl_close(sock);
@@ -221,20 +242,28 @@ int netlink_init(void)
 	return ret;
 }
 
-void netlink_loop(void)
+int netlink_interface_create(struct interface *intf)
 {
-	pthread_join(nl_recv_thread, NULL);
+	intf->id = 0;
+
+	return 0;
 }
 
-void netlink_cancel(void)
+void netlink_exit(struct controller * ctrl)
 {
 	svc_watchdog_disable();
 	pthread_cancel(nl_recv_thread);
-}
+	pthread_join(nl_recv_thread, NULL);
 
-void netlink_exit(void)
-{
 	netlink_hd_reset();
 	nl_close(sock);
 	nl_socket_free(sock);
 }
+
+struct controller netlink_controller = {
+	.name = "netlink",
+	.init = netlink_init,
+	.exit = netlink_exit,
+	.write = netlink_write,
+	.interface_create = netlink_interface_create,
+};
\ No newline at end of file
diff --git a/netlink.h b/controllers/netlink.h
similarity index 100%
rename from netlink.h
rename to controllers/netlink.h
diff --git a/greybus.c b/greybus.c
index 1afa19c..977de00 100644
--- a/greybus.c
+++ b/greybus.c
@@ -25,7 +25,6 @@
 #include <gb_netlink.h>
 
 #include "gbridge.h"
-#include "netlink.h"
 #include "controller.h"
 
 static TAILQ_HEAD(operation_head, operation) operations;
@@ -168,7 +167,7 @@ int greybus_send_request(uint8_t intf_id, uint16_t cport_id,
 
 	op->cport_id = cport_id;
 	TAILQ_INSERT_TAIL(&operations, op, cnode);
-	ret = netlink_send(cport_id, op->req, len);
+	ret = controller_write(intf_id, cport_id, op->req, len);
 	if (ret < 0)
 		return ret;
 
@@ -184,7 +183,7 @@ static int greybus_send_response(uint8_t intf_id, uint16_t cport_id,
 	len = gb_operation_msg_size(op->resp);
 	pr_dump(op->resp, len);
 
-	ret = netlink_send(cport_id, op->resp, len);
+	ret = controller_write(intf_id, cport_id, op->resp, len);
 	if (ret < 0)
 		return ret;
 
diff --git a/main.c b/main.c
index 51c54ae..c283a19 100644
--- a/main.c
+++ b/main.c
@@ -24,9 +24,10 @@
 #include <controller.h>
 
 #include "gbridge.h"
-#include "netlink.h"
 #include "controllers/uart.h"
 
+int run;
+
 static void help(void)
 {
 	printf("gbridge: Greybus bridge application\n"
@@ -41,7 +42,7 @@ static void help(void)
 
 static void signal_handler(int sig)
 {
-	netlink_cancel();
+	run = 0;
 }
 
 int main(int argc, char *argv[])
@@ -79,40 +80,17 @@ int main(int argc, char *argv[])
 		return ret;
 	}
 
-	ret = netlink_init();
-	if (ret) {
-		pr_err("Failed to init netlink\n");
-		return ret;
-	}
-
-	ret = svc_init();
-	if (ret) {
-		pr_err("Failed to init SVC\n");
-		goto err_netlink_exit;
-	}
-
 	if (uart) {
 		ret = register_uart_controller(uart, baudrate);
-		if (ret) {
-			pr_err("Failed to init uart controller\n");
-			goto err_netlink_exit;
-		}
+		if (ret)
+			return ret;
 	}
 
+	run = 1;
 	controllers_init();
-
-	netlink_loop();
-
+	while(run)
+		sleep(1);
 	controllers_exit();
 
-	netlink_exit();
-
 	return 0;
-
- err_netlink_exit:
-	netlink_cancel();
-	netlink_loop();
-	netlink_exit();
-
-	return ret;
 }
-- 
GitLab