[rdkb][common][app][Refactor switch tool]

[Description]
Refactor switch tool
1. align to newest openwrt version
2. add a patch to change the differences between openwrt and RDKB such as bridge name ...

[Release-log]

Change-Id: Iaba64709f3be51a2764b5374c043aa793596721d
diff --git a/recipes-devtools/switch/files/src/switch_netlink.c b/recipes-devtools/switch/files/src/switch_netlink.c
new file mode 100644
index 0000000..90a4a19
--- /dev/null
+++ b/recipes-devtools/switch/files/src/switch_netlink.c
@@ -0,0 +1,445 @@
+/*
+ * switch_netlink.c: switch(netlink) set API
+ *
+ * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+
+#include "switch_netlink.h"
+
+static struct nl_sock *user_sock;
+static struct nl_cache *cache;
+static struct genl_family *family;
+static struct nlattr *attrs[MT753X_ATTR_TYPE_MAX + 1];
+
+static int wait_handler(struct nl_msg *msg, void *arg)
+{
+	int *finished = arg;
+
+	*finished = 1;
+	return NL_STOP;
+}
+
+static int list_swdevs(struct nl_msg *msg, void *arg)
+{
+	struct mt753x_attr *val = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+	if (nla_parse(attrs, MT753X_ATTR_TYPE_MAX, genlmsg_attrdata(gnlh, 0),
+		      genlmsg_attrlen(gnlh, 0), NULL) < 0)
+		goto done;
+
+	if (gnlh->cmd == MT753X_CMD_REPLY) {
+		if (attrs[MT753X_ATTR_TYPE_MESG]) {
+			val->dev_info =
+				nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
+			printf("register switch dev:\n%s", val->dev_info);
+		}
+		else {
+			fprintf(stderr, "ERROR:No switch dev now\n");
+			goto done;
+		}
+	} else
+		goto done;
+	return 0;
+done:
+	return NL_SKIP;
+}
+
+static int construct_attrs(struct nl_msg *msg, void *arg)
+{
+	struct mt753x_attr *val = arg;
+	int type = val->type;
+
+	if (val->dev_id > -1)
+		NLA_PUT_U32(msg, MT753X_ATTR_TYPE_DEV_ID, val->dev_id);
+
+	if (val->op == 'r') {
+		if (val->phy_dev != -1)
+			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
+		if (val->port_num >= 0)
+			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
+		NLA_PUT_U32(msg, type, val->reg);
+	} else if (val->op == 'w') {
+		if (val->phy_dev != -1)
+			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
+		if (val->port_num >= 0)
+			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
+		NLA_PUT_U32(msg, type, val->reg);
+		NLA_PUT_U32(msg, MT753X_ATTR_TYPE_VAL, val->value);
+	} else {
+		printf("construct_attrs_message\n");
+		NLA_PUT_STRING(msg, type, "hello");
+	}
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int spilt_attrs(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct mt753x_attr *val = arg;
+	char *str;
+
+	if (nla_parse(attrs, MT753X_ATTR_TYPE_MAX, genlmsg_attrdata(gnlh, 0),
+		      genlmsg_attrlen(gnlh, 0), NULL) < 0)
+		goto done;
+
+	if ((gnlh->cmd == MT753X_CMD_WRITE) || (gnlh->cmd == MT753X_CMD_READ)) {
+		if (attrs[MT753X_ATTR_TYPE_MESG]) {
+			str = nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
+			printf(" %s\n", str);
+			if (!strncmp(str, "No", 2))
+				goto done;
+		}
+		if (attrs[MT753X_ATTR_TYPE_REG]) {
+			val->reg =
+			    nla_get_u32(attrs[MT753X_ATTR_TYPE_REG]);
+		}
+		if (attrs[MT753X_ATTR_TYPE_VAL]) {
+			val->value =
+			    nla_get_u32(attrs[MT753X_ATTR_TYPE_VAL]);
+		}
+	}
+	else
+		goto done;
+
+	return 0;
+done:
+	return NL_SKIP;
+}
+
+static int mt753x_request_callback(int cmd, int (*spilt)(struct nl_msg *, void *),
+				   int (*construct)(struct nl_msg *, void *),
+				   void *arg)
+{
+	struct nl_msg *msg;
+	struct nl_cb *callback = NULL;
+	int finished;
+	int flags = 0;
+	int err;
+
+	/*Allocate an netllink message buffer*/
+	msg = nlmsg_alloc();
+	if (!msg) {
+		fprintf(stderr, "Failed to allocate netlink message\n");
+		exit(1);
+	}
+	if (!construct) {
+		if (cmd == MT753X_CMD_REQUEST)
+			flags |= NLM_F_REQUEST;
+		else
+			flags |= NLM_F_DUMP;
+	}
+	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family),
+		    0, flags, cmd, 0);
+
+	/*Fill attaribute of netlink message by construct function*/
+	if (construct) {
+		err = construct(msg, arg);
+		if (err < 0) {
+			fprintf(stderr, "attributes error\n");
+			goto nal_put_failure;
+		}
+	}
+
+	/*Allocate an new callback handler*/
+	callback = nl_cb_alloc(NL_CB_CUSTOM);
+	if (!callback) {
+		fprintf(stderr, "Failed to allocate callback handler\n");
+		exit(1);
+	}
+
+	/*Send netlink message*/
+	err = nl_send_auto_complete(user_sock, msg);
+	if (err < 0) {
+		fprintf(stderr, "nl_send_auto_complete failied:%d\n", err);
+		goto out;
+	}
+	finished = 0;
+	if (spilt)
+		nl_cb_set(callback, NL_CB_VALID, NL_CB_CUSTOM, spilt, arg);
+
+	if (construct)
+		nl_cb_set(callback, NL_CB_ACK, NL_CB_CUSTOM, wait_handler,
+			  &finished);
+	else
+		nl_cb_set(callback, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler,
+			  &finished);
+
+	/*receive message from kernel request*/
+	err = nl_recvmsgs(user_sock, callback);
+	if (err < 0)
+		goto out;
+
+	/*wait until an ACK is received for the latest not yet acknowledge*/
+	if (!finished)
+		err = nl_wait_for_ack(user_sock);
+out:
+	if (callback)
+		nl_cb_put(callback);
+
+nal_put_failure:
+	nlmsg_free(msg);
+	return err;
+}
+
+void mt753x_netlink_free(void)
+{
+	if (family)
+		nl_object_put((struct nl_object *)family);
+	if (cache)
+		nl_cache_free(cache);
+	if (user_sock)
+		nl_socket_free(user_sock);
+	user_sock = NULL;
+	cache = NULL;
+	family = NULL;
+}
+
+int mt753x_netlink_init(const char *name)
+{
+	int ret;
+
+	user_sock = NULL;
+	cache = NULL;
+	family = NULL;
+
+	/*Allocate an new netlink socket*/
+	user_sock = nl_socket_alloc();
+	if (!user_sock) {
+		fprintf(stderr, "Failed to create user socket\n");
+		goto err;
+	}
+	/*Connetct the genl controller*/
+	if (genl_connect(user_sock)) {
+		fprintf(stderr, "Failed to connetct to generic netlink\n");
+		goto err;
+	}
+	/*Allocate an new nl_cache*/
+	ret = genl_ctrl_alloc_cache(user_sock, &cache);
+	if (ret < 0) {
+		fprintf(stderr, "Failed to allocate netlink cache\n");
+		goto err;
+	}
+
+	if (name == NULL)
+		return -EINVAL;
+
+	/*Look up generic netlik family by "mt753x" in the provided cache*/
+	family = genl_ctrl_search_by_name(cache, name);
+	if (!family) {
+		//fprintf(stderr,"switch(mt753x) API not be prepared\n");
+		goto err;
+	}
+	return 0;
+err:
+	mt753x_netlink_free();
+	return -EINVAL;
+}
+
+void mt753x_list_swdev(struct mt753x_attr *arg, int cmd)
+{
+	int err;
+
+	err = mt753x_request_callback(cmd, list_swdevs, NULL, arg);
+	if (err < 0)
+		fprintf(stderr, "mt753x list dev error\n");
+}
+
+static int mt753x_request(struct mt753x_attr *arg, int cmd)
+{
+	int err;
+
+	err = mt753x_request_callback(cmd, spilt_attrs, construct_attrs, arg);
+	if (err < 0) {
+		fprintf(stderr, "mt753x deal request error\n");
+		return err;
+	}
+	return 0;
+}
+
+static int phy_operate_netlink(char op, struct mt753x_attr *arg,
+			       unsigned int port_num, unsigned int phy_dev,
+			       unsigned int offset, unsigned int *value)
+{
+	int ret = 0;
+	struct mt753x_attr *attr = arg;
+
+	attr->port_num = port_num;
+	attr->phy_dev = phy_dev;
+	attr->reg = offset;
+	attr->value = -1;
+	attr->type = MT753X_ATTR_TYPE_REG;
+
+	switch (op)
+	{
+		case 'r':
+			attr->op = 'r';
+			ret = mt753x_request(attr, MT753X_CMD_READ);
+			*value = attr->value;
+			break;
+		case 'w':
+			attr->op = 'w';
+			attr->value = *value;
+			ret = mt753x_request(attr, MT753X_CMD_WRITE);
+			break;
+		default:
+			break;
+	}
+
+	return ret;
+}
+
+int reg_read_netlink(struct mt753x_attr *arg, unsigned int offset,
+		     unsigned int *value)
+{
+	int ret;
+
+	ret = phy_operate_netlink('r', arg, -1, -1, offset, value);
+	return ret;
+}
+
+int reg_write_netlink(struct mt753x_attr *arg, unsigned int offset,
+		      unsigned int value)
+{
+	int ret;
+
+	ret = phy_operate_netlink('w', arg, -1, -1, offset, &value);
+	return ret;
+}
+
+int phy_cl22_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
+			  unsigned int phy_addr, unsigned int *value)
+{
+	int ret;
+
+	ret = phy_operate_netlink('r', arg, port_num, -1, phy_addr, value);
+	return ret;
+}
+
+int phy_cl22_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
+			   unsigned int phy_addr, unsigned int value)
+{
+	int ret;
+
+	ret = phy_operate_netlink('w', arg, port_num, -1, phy_addr, &value);
+	return ret;
+}
+
+int phy_cl45_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
+			  unsigned int phy_dev, unsigned int phy_addr,
+			  unsigned int *value)
+{
+	int ret;
+
+	ret = phy_operate_netlink('r', arg, port_num, phy_dev, phy_addr, value);
+	return ret;
+}
+
+int phy_cl45_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
+			   unsigned int phy_dev, unsigned int phy_addr,
+			   unsigned int value)
+{
+	int ret;
+
+	ret = phy_operate_netlink('w', arg, port_num, phy_dev, phy_addr, &value);
+	return ret;
+}
+
+void dump_extend_phy_reg(struct mt753x_attr *arg, int port_no, int from,
+			int to, int is_local, int page_no)
+{
+        unsigned int temp = 0;
+        int r31 = 0;
+        int i = 0;
+
+        if (is_local == 0) {
+            printf("\n\nGlobal Register Page %d\n",page_no);
+            printf("===============");
+            r31 |= 0 << 15; //global
+            r31 |= ((page_no&0x7) << 12); //page no
+            phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
+            for (i = 16; i < 32; i++) {
+                if(i%8 == 0)
+                    printf("\n");
+		phy_cl22_read_netlink(arg, port_no, i, &temp);
+                printf("%02d: %04X ", i, temp);
+            }
+        } else {
+            printf("\n\nLocal Register Port %d Page %d\n",port_no, page_no);
+            printf("===============");
+            r31 |= 1 << 15; //local
+            r31 |= ((page_no&0x7) << 12); //page no
+            phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
+            for (i = 16; i < 32; i++) {
+                if (i%8 == 0) {
+                    printf("\n");
+                }
+		phy_cl22_read_netlink(arg, port_no, i, &temp);
+                printf("%02d: %04X ",i, temp);
+            }
+        }
+        printf("\n");
+}
+
+int phy_dump_netlink(struct mt753x_attr *arg, int phy_addr)
+{
+	int i;
+	int ret;
+	unsigned int offset, value;
+
+	if (phy_addr == 32) {
+		/*dump all phy register*/
+		for (i = 0; i < 5; i++) {
+			printf("\n[Port %d]=============", i);
+			for (offset = 0; offset < 16; offset++) {
+				if (offset % 8 == 0)
+					printf("\n");
+				ret = phy_cl22_read_netlink(arg, i, offset, &value);
+				printf("%02d: %04X ", offset, value);
+			}
+		}
+	} else {
+		printf("\n[Port %d]=============", phy_addr);
+		for (offset = 0; offset < 16; offset++) {
+			if (offset % 8 == 0)
+				printf("\n");
+			ret = phy_cl22_read_netlink(arg, phy_addr, offset, &value);
+			printf("%02d: %04X ", offset, value);
+		}
+	}
+	printf("\n");
+	for (offset = 0; offset < 5; offset++) { //global register  page 0~4
+		if (phy_addr == 32) //dump all phy register
+			dump_extend_phy_reg(arg, 0, 16, 31, 0, offset);
+		else
+			dump_extend_phy_reg(arg, phy_addr, 16, 31, 0, offset);
+	}
+
+	if (phy_addr == 32) {	//dump all phy register
+		for (offset = 0; offset < 5; offset++) { //local register port 0-port4
+			dump_extend_phy_reg(arg, offset, 16, 31, 1, 0); //dump local page 0
+			dump_extend_phy_reg(arg, offset, 16, 31, 1, 1); //dump local page 1
+			dump_extend_phy_reg(arg, offset, 16, 31, 1, 2); //dump local page 2
+			dump_extend_phy_reg(arg, offset, 16, 31, 1, 3); //dump local page 3
+		}
+	} else {
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 0); //dump local page 0
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 1); //dump local page 1
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 2); //dump local page 2
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 3); //dump local page 3
+	}
+	return ret;
+}