ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/services/piped/piped_dhcp.c b/marvell/services/piped/piped_dhcp.c
new file mode 100644
index 0000000..2835a32
--- /dev/null
+++ b/marvell/services/piped/piped_dhcp.c
@@ -0,0 +1,270 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "piped.h"
+#include "piped_uci.h"
+#include "piped_util.h"
+#include "piped_nw.h"
+#include "piped_dhcp.h"
+#include "piped_dns.h"
+
+extern struct piped pd;
+
+static int pd_dhcp_set_limit(struct pd_context *pdc, int start_second, int start_third, int start, int limit)
+{
+	char startb[16];
+	char limitb[4];
+	struct uci_context *c = pdc->c;
+
+	if (start != 255 && start != 0) {
+		sprintf(startb, "%d", start);
+	} else {
+		if (start_third != 255 && start_third != 0)
+			sprintf(startb, "%d.%d", start_third, start);
+		else
+			sprintf(startb, "%d.%d.%d", start_second, start_third, start);
+	}
+	sprintf(limitb, "%d", limit);
+
+	if (pd_uci_set_opt(c, UCI_PKG_DHCP, UCI_SEC_LAN, UCI_OPT_START,
+			   startb)) {
+		PD_ERR(pd_dhcp_set_limit, "pd_uci_set_opt failed %s\n", startb);
+		return 1;
+	}
+	if (pd_uci_set_opt(c, UCI_PKG_DHCP, UCI_SEC_LAN, UCI_OPT_LIMIT,
+			   limitb)) {
+		PD_ERR(pd_dhcp_set_limit1, "pd_uci_set_opt failed %s\n", limitb);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void pd_fast_dhcp_reply(char *ipaddr)
+{
+	char cmd[100] = {0};
+	char buf[10] = {0};
+	int vlan_or_eth = 0;
+	FILE *fp = NULL;
+	static char saved_ipaddr[MAX_IP_STR_LEN] = {0};
+	char *line = NULL;
+
+	pd_system("cat /sys/kernel/mpipe/devices/all | grep ccinet | grep Up4 | wc -l > /tmp/piped_count");
+
+	fp = fopen("/tmp/piped_count", "r");
+	if (!fp)
+		return;
+
+	line = fgets(buf, sizeof(buf), fp);
+	if (!line) {
+		fclose(fp);
+		return;
+	}
+	fclose(fp);
+	if (atoi(buf) > 1)
+		vlan_or_eth = 1;
+
+	if (vlan_or_eth) {
+		pd_system("uci set dhcp.@dnsmasq[0].readethers=0 && uci commit dhcp");
+		return;
+	}
+
+	if (!strncasecmp(ipaddr, saved_ipaddr, MAX_IP_STR_LEN))
+		return;
+
+	pd_system("head -n 1 /etc/ethers | cut -c -17 > /tmp/piped_ethers");
+	sprintf(cmd, "sed -i 's/$/& %s/g' /tmp/piped_ethers", ipaddr);
+	pd_system(cmd);
+	pd_system("cat /tmp/piped_ethers > /etc/ethers");
+	pd_system("uci set dhcp.@dnsmasq[0].readethers=1 && uci commit dhcp");
+	memcpy(saved_ipaddr, ipaddr, MAX_IP_STR_LEN);
+	return;
+}
+
+static int pd_dhcp_add_del_snmask(struct pd_context *pdc, bool add, int last_oct, int third_oct )
+{
+	struct uci_context *c = pdc->c;
+	char options[MAX_DHCP_OPT_STR_LEN];
+
+	strcpy(options, UCI_DHCP_OPTNUM_SNMASK);
+	strcat(options, ",");
+	if (last_oct != 255 && last_oct != 0)
+		strcat(options, UCI_DHCP_DFLT_SNMASK);
+	else {
+		if (third_oct != 255 && third_oct != 0)
+			strcat(options, UCI_DHCP_DFLT_SNMASK1);
+		else 
+			strcat(options, UCI_DHCP_DFLT_SNMASK2);
+	}
+
+	if (add && pd_uci_add_list(c, UCI_PKG_DHCP, UCI_SEC_LAN,
+				   UCI_OPT_DHCP_OPT, options)) {
+		PD_ERR(pd_dhcp_add_del_snmask, "pd_uci_add_list failed %s\n", options);
+		return 1;
+	} else if (!add && pd_uci_del_from_list(c, UCI_PKG_DHCP, UCI_SEC_LAN,
+						UCI_OPT_DHCP_OPT, options)) {
+		PD_ERR(pd_dhcp_add_del_snmask1, "pd_uci_del_from_list failed %s\n", options);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int pd_dhcp_add_del_gw(struct pd_context *pdc, char *gw, bool add)
+{
+	struct uci_context *c = pdc->c;
+	char options[MAX_DHCP_OPT_STR_LEN];
+	size_t options_len, gw_len;
+
+	strcpy(options, UCI_DHCP_OPTNUM_GW);
+	strcat(options, ",");
+	options_len = strlen(options);
+	gw_len = strlen(gw);
+	if(options_len + gw_len < sizeof(options)) {
+		strcat(options, gw);
+	} else {
+		return -1;
+	}
+
+	if (!add && pd_uci_del_from_list(c, UCI_PKG_DHCP, UCI_SEC_LAN,
+					UCI_OPT_DHCP_OPT, options)) {
+		PD_ERR(pd_dhcp_add_del_gw, "pd_uci_del_from_list failed %s\n", options);
+		return 1;
+	} else if (add && pd_uci_add_list(c, UCI_PKG_DHCP, UCI_SEC_LAN,
+					   UCI_OPT_DHCP_OPT, options)) {
+		PD_ERR(pd_dhcp_add_del_gw1, "pd_uci_add_list failed %s\n", options);
+		return 1;
+	}
+	return 0;
+}
+
+int pd_dhcp_add(struct pd_context *pdc, struct pd_iface *pdi)
+{
+	char *gw;
+	int dhcp_start;
+	int dhcp_third;
+	int dhcp_second;
+	char lan_alias[MAX_IP_STR_LEN];
+
+	dhcp_start = ipv4_get_last_oct(pdi->ipaddr);
+	dhcp_third = ipv4_get_third_oct(pdi->ipaddr);
+	dhcp_second = ipv4_get_second_oct(pdi->ipaddr);
+	
+	if (pd.rand_gw) {
+		ipv4_get_alias(pdi->ipaddr, lan_alias);
+		gw = lan_alias;
+	} else {
+		gw = pdi->ipaddr;
+	}
+	PD_ERR(pd_dhcp_add_m0,"pd_dhcp_add: gw=%s, dhcp_start=%d\n", gw, dhcp_start);
+	if (pd_dhcp_set_limit(pdc, dhcp_second, dhcp_third, dhcp_start, 1)) {
+		PD_ERR(pd_dhcp_add, "pd_dhcp_set_limit failed start %d, limit 1\n",
+			dhcp_start);
+		return 1;
+	}
+
+	pd_fast_dhcp_reply(pdi->ipaddr);
+
+	if (pd_dhcp_add_del_gw(pdc, gw, true)) {
+		PD_ERR(pd_dhcp_add1, "pd_dhcp_add_del_gw failed %s\n", gw);
+		return 1;
+	}
+
+	if (pd_dhcp_add_del_snmask(pdc, true, dhcp_start, dhcp_third)) {
+		PD_ERR(pd_dhcp_add2, "pd_dhcp_add_del_snmask failed\n");
+		return 1;
+	}
+
+	pd_set(&pdc->status, PDC_DNSMASQ_CHANGED);
+
+	return 0;
+}
+
+int pd_dhcp_del(struct pd_context *pdc, struct pd_iface *pdi)
+{
+	char *gw;
+	char lan_alias[MAX_IP_STR_LEN];
+	int dhcp_start;
+	int dhcp_third;
+
+	dhcp_start = ipv4_get_last_oct(pdi->ipaddr);	
+	dhcp_third = ipv4_get_third_oct(pdi->ipaddr);	
+	
+
+	if (pd.rand_gw) {
+		ipv4_get_alias(pdi->ipaddr, lan_alias);
+		gw = lan_alias;
+	} else {
+		gw = pdi->ipaddr;
+	}
+	PD_ERR(pd_dhcp_del_m0, "pd_dhcp_del: gw=%s\n", gw);
+	if (pd_dhcp_set_limit(pdc, 1, 1, UCI_DHCP_DFLT_START, UCI_DHCP_DFLT_LIMIT)) {
+		PD_ERR(pd_dhcp_del, "pd_dhcp_set_limit failed start %d, limit %d\n",
+			UCI_DHCP_DFLT_START, UCI_DHCP_DFLT_LIMIT);
+		return 1;
+	}
+
+	if (pd_dhcp_add_del_gw(pdc, gw, false)) {
+		PD_ERR(pd_dhcp_del1, "pd_dhcp_add_del_gw failed %s\n", gw);
+		return 1;
+	}
+
+	if (pd_dhcp_add_del_snmask(pdc, false, dhcp_start, dhcp_third)) {
+		PD_ERR(pd_dhcp_del2, "pd_dhcp_add_del_snmask failed\n");
+		return 1;
+	}
+
+	pd_set(&pdc->status, PDC_DNSMASQ_CHANGED);
+
+	return 0;
+}
+
+
+int pd_dhcp_change(struct pd_context *pdc, struct pd_iface *oldi,
+		  struct pd_iface *newi)
+{
+	if (pd_dhcp_del(pdc, oldi)) {
+		PD_ERR(pd_dhcp_change, "pd_dhcp_del failed for %s\n", oldi->sec);
+		return 1;
+	}
+	if (pd_dhcp_add(pdc, newi)) {
+		PD_ERR(pd_dhcp_change1, "pd_dhcp_add failed for %s\n", newi->sec);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+void pd_dhcp_clean(struct pd_context *pdc)
+{
+	struct uci_context *c = pdc->c;
+	char *s = pd_uci_get_opt(c, UCI_PKG_DHCP, UCI_SEC_LAN, UCI_OPT_START);
+	char *l = pd_uci_get_opt(c, UCI_PKG_DHCP, UCI_SEC_LAN, UCI_OPT_LIMIT);
+
+	if (!s || (atoi(s) != UCI_DHCP_DFLT_START) ||
+	    !l || (atoi(l) != UCI_DHCP_DFLT_LIMIT))
+		goto do_clean;
+
+	return;
+
+
+do_clean:
+
+	PD_INFO(pd_dhcp_clean, "cleaning dhcp configuration\n");
+
+	if (pd_dhcp_set_limit(pdc, 1, 1, UCI_DHCP_DFLT_START, UCI_DHCP_DFLT_LIMIT)) {
+		PD_ERR(pd_dhcp_clean1, "pd_dhcp_set_limit failed\n");
+		return;
+	}
+
+	pd_uci_del(c, UCI_PKG_DHCP, UCI_SEC_LAN, UCI_OPT_DHCP_OPT, NULL);
+
+	pd_set(&pdc->status, PDC_DNSMASQ_CHANGED);
+}