blob: 2835a32a733e3cef81e4b116bb188f34f4043350 [file] [log] [blame]
#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);
}