| #include "router_settings.h" |
| |
| enum { |
| OPT_GATEWAY_TYPE = 3, |
| OPT_DNS_TYPE = 6, |
| }; |
| |
| struct up_ifa_name { |
| char *name; |
| struct up_ifa_name *next; |
| }; |
| |
| /*get Router Gateway*/ |
| static int parse_dhcp_option_str(char *option_str, struct blob_buf *buf, int *option_type) |
| { |
| #define space_char 32 |
| #define MAX_VALUE_BUF_SIZE 128 |
| |
| char *entry_start = NULL; |
| char *entry_end = NULL; |
| char *del_pos = NULL; |
| int ret_val = 0; |
| char *value_buf = NULL; |
| char tmp[4] = { 0 }; |
| int opt_type = 0; |
| |
| if (!option_str) { |
| ret_val = 1; |
| goto EXIT; |
| } |
| entry_start = option_str; |
| while (*entry_start != space_char) { |
| break; |
| entry_start++; |
| } |
| ROUTER_DBG("entry_start %x, %s", entry_start, entry_start); |
| while (*entry_start) { |
| entry_end = strchr(option_str, space_char); |
| if (!entry_end) { |
| entry_end = entry_start + strlen(entry_start) - 1; |
| } |
| |
| ROUTER_DBG("entry_start %x, entry_end %x", entry_start, entry_end); |
| del_pos = strchr(entry_start, ','); |
| if (del_pos) { |
| if (del_pos - entry_start < 4) { |
| memset(tmp, 0, 4); |
| memcpy(tmp, entry_start, del_pos - entry_start); |
| opt_type = atoi(tmp); |
| *option_type = opt_type; |
| ROUTER_DBG("dhcp option type is %s, %d", tmp, opt_type); |
| if (buf) { |
| //value_buf = malloc(entry_end - del_pos + 1); |
| value_buf = malloc(MAX_VALUE_BUF_SIZE); |
| if (value_buf) { |
| //memset(value_buf, 0, entry_end - del_pos + 1); |
| memset(value_buf, 0, MAX_VALUE_BUF_SIZE); |
| if (*(del_pos + 1) == ',' && *(del_pos + 2) == '6' && *(del_pos + 3) == ',') |
| { |
| /* skip ",,6," */ |
| del_pos += 4; |
| snprintf(value_buf, MAX_VALUE_BUF_SIZE - 1, "disable,%s", del_pos); |
| } |
| else |
| { |
| del_pos += 1; |
| snprintf(value_buf, MAX_VALUE_BUF_SIZE - 1, "%s", del_pos); |
| } |
| //memcpy(value_buf, del_pos + 1, entry_end - del_pos); |
| ROUTER_DBG("dhcp option value : %s", value_buf); |
| switch (opt_type) { |
| case OPT_GATEWAY_TYPE: |
| blobmsg_add_string(buf, "option_gateway", value_buf); |
| break; |
| case OPT_DNS_TYPE: |
| blobmsg_add_string(buf, "option_dns", value_buf); |
| break; |
| } |
| free(value_buf); |
| } |
| } |
| } |
| } else { |
| /*with out value, this option is disabled */ |
| if (entry_end - entry_start < 4) { |
| memset(tmp, 0, 4); |
| memcpy(tmp, entry_start, entry_end - entry_start + 1); |
| opt_type = atoi(tmp); |
| *option_type = opt_type; |
| ROUTER_DBG("dhcp option type entry_start %x, entry_end %x, is %s, %d",entry_start, entry_end, tmp, opt_type); |
| if (buf) { |
| switch (opt_type) { |
| case OPT_GATEWAY_TYPE: |
| blobmsg_add_string(buf, "option_gateway", "disable"); |
| break; |
| case OPT_DNS_TYPE: |
| blobmsg_add_string(buf, "option_dns", "disable"); |
| break; |
| } |
| } |
| break; |
| } |
| } |
| /*get next first non space character */ |
| while (*++entry_end != space_char) { |
| entry_start = entry_end; |
| if (*entry_start == '\0') |
| break; |
| } |
| } |
| EXIT: |
| return ret_val; |
| } |
| |
| /*================================================ |
| When the service starts to run, check whether the dhcp-option is included |
| in file /etc/config/dhcp,if not included, add then please |
| ================================================*/ |
| void check_add_dhcp_option(void) |
| { |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| struct uci_option *list_opt = NULL; |
| struct uci_option *uci_opt = NULL; |
| struct uci_element *e_list = NULL; |
| struct uci_ptr set_ptr; |
| const char *opt_val = NULL; |
| int opt_type = 0; |
| int gateway_find = 0; |
| int dns_find = 0; |
| |
| ROUTER_DBG("enter"); |
| /*load /etc/config/dhcp */ |
| local_ctx = (struct uci_context *)uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| ROUTER_DBG("get uci ctx OK\r\n"); |
| |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, DHCP_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| if (!p) { |
| uci_load(local_ctx, DHCP_PACK, &p); |
| } |
| if (p) { |
| |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (strcmp(uci_sec->type, "dhcp") == 0) { |
| ROUTER_DBG("got one dhcp section"); |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "interface"); |
| if (opt_val && (strcmp(opt_val, "lan") == 0)) { |
| ROUTER_DBG("got the dhcp pool settings"); |
| list_opt = uci_lookup_option(local_ctx, uci_sec, "dhcp_option"); |
| if (list_opt && list_opt->type == UCI_TYPE_LIST) { |
| |
| uci_foreach_element(&list_opt->v.list, e_list) { |
| uci_opt = uci_to_option(e_list); |
| if (uci_opt->e.name) { |
| ROUTER_DBG("got one option : %s", uci_opt->e.name); |
| parse_dhcp_option_str(uci_opt->e.name, NULL, &opt_type); |
| switch (opt_type) { |
| case OPT_GATEWAY_TYPE: |
| gateway_find = 1; |
| break; |
| case OPT_DNS_TYPE: |
| dns_find = 1; |
| break; |
| } |
| } |
| } |
| } |
| /*add DHCP-GATEWAY */ |
| if (gateway_find == 0) { |
| memset(&set_ptr, 0, sizeof(struct uci_ptr)); |
| set_ptr.p = p; |
| set_ptr.s = uci_sec; |
| set_ptr.option = "dhcp_option"; |
| set_ptr.value = "3"; |
| uci_add_list(local_ctx, &set_ptr); |
| } |
| if (dns_find == 0) { |
| memset(&set_ptr, 0, sizeof(struct uci_ptr)); |
| set_ptr.p = p; |
| set_ptr.s = uci_sec; |
| set_ptr.option = "dhcp_option"; |
| set_ptr.value = "6"; |
| uci_add_list(local_ctx, &set_ptr); |
| } |
| break; |
| } |
| } |
| } |
| uci_commit(local_ctx, &p, false); |
| } |
| free_router_uci_ctx(); |
| } |
| |
| #if 1 |
| static void set_dhcp_option_value(struct uci_context *in_ctx, struct uci_package *p, struct uci_section *in_sec, |
| int in_type, char *msg_value) |
| { |
| struct uci_option *uci_opt_list = NULL; |
| struct uci_option *uci_opt = NULL; |
| struct uci_element *e_list = NULL; |
| struct uci_ptr ptr; |
| int opt_type = 0; |
| char option_value[100] = { 0 }; |
| bool list_exist = false; |
| bool valid_value = false; |
| char *pValue = NULL; |
| |
| if (!in_ctx || !p || !in_sec || !msg_value) |
| return; |
| |
| ROUTER_DBG("in_type %d, msg_value : %s", in_type, msg_value); |
| memset(option_value, 0, sizeof(option_value)); |
| pValue = strstr(msg_value, "disable"); |
| if ( pValue == NULL) |
| { |
| valid_value = true; |
| snprintf(option_value, sizeof(option_value) - 1, "%d,%s", in_type, msg_value); |
| } |
| else |
| { |
| if (in_type == OPT_DNS_TYPE) |
| { |
| if (pValue == msg_value) |
| { |
| if (!strcmp(msg_value, "disable") ||!strcmp(msg_value, "disable,disable")) |
| { |
| /* disable dns */ |
| } |
| else |
| { |
| /* primary dns disable */ |
| pValue += strlen("disable,"); |
| snprintf(option_value, sizeof(option_value) - 1, "%d,,%d,%s", in_type, in_type, pValue); |
| valid_value = true; |
| } |
| } |
| else |
| { |
| /* secondary dns disable */ |
| pValue = strchr(msg_value, ','); |
| if (pValue) |
| { |
| int len = (pValue - msg_value); |
| int size = snprintf(option_value, sizeof(option_value) - 1, "%d,", in_type); |
| memcpy(option_value + size, msg_value, len); |
| valid_value = true; |
| } |
| } |
| } |
| } |
| /*dhcp_option list */ |
| uci_opt_list = uci_lookup_option(in_ctx, in_sec, "dhcp_option"); |
| if (uci_opt_list && uci_opt_list->type == UCI_TYPE_LIST) { |
| uci_foreach_element(&uci_opt_list->v.list, e_list) { |
| uci_opt = uci_to_option(e_list); |
| if (uci_opt->e.name) { |
| ROUTER_DBG("got one option : %s", uci_opt->e.name); |
| parse_dhcp_option_str(uci_opt->e.name, NULL, &opt_type); |
| if (in_type == opt_type) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.s = in_sec; |
| ptr.p = p; |
| ptr.o = uci_opt_list; |
| ptr.value = uci_opt->e.name; |
| uci_del_list(in_ctx, &ptr); |
| |
| if (valid_value) |
| { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.s = in_sec; |
| ptr.p = p; |
| ptr.o = uci_opt_list; |
| |
| //memset(option_value, 0, sizeof(option_value)); |
| //snprintf(option_value, sizeof(option_value) - 1, "%d,%s", in_type, msg_value); |
| ROUTER_DBG("update list value %s", option_value); |
| ptr.value = option_value; |
| uci_add_list(in_ctx, &ptr); |
| } |
| list_exist = true; |
| break; |
| } |
| } |
| } |
| } |
| |
| if (!list_exist && valid_value) |
| { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.s = in_sec; |
| ptr.p = p; |
| ptr.option = "dhcp_option"; |
| |
| //memset(option_value, 0, sizeof(option_value)); |
| //snprintf(option_value, sizeof(option_value) - 1, "%d,%s", in_type, msg_value); |
| ROUTER_DBG("new list value %s", option_value); |
| ptr.value = option_value; |
| uci_add_list(in_ctx, &ptr); |
| } |
| } |
| #endif |
| /*get router lan ip*/ |
| /*================================================ |
| <router> |
| <lan_ip/> |
| </router> |
| Note : the dhcp settings is only included in config 'dhcp' 'lan' |
| ================================================*/ |
| int router_get_lan_ip_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| const char *opt_val = NULL; |
| void *tb_router = NULL; |
| |
| UNUSESET(obj); |
| UNUSESET(method); |
| UNUSESET(msg); |
| ROUTER_DBG("enter"); |
| /*load /etc/config/network */ |
| local_ctx = (struct uci_context *)uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| ROUTER_DBG("get uci ctx OK\r\n"); |
| |
| blobmsg_buf_init(&router_buf); |
| tb_router = blobmsg_open_table(&router_buf, "router"); |
| |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, NW_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| if (!p) { |
| uci_load(local_ctx, NW_PACK, &p); |
| } |
| if (p) { |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (strcmp(uci_sec->type, "interface") == 0) { |
| if (uci_sec->e.name && strcmp(uci_sec->e.name, "lan") == 0) { |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "ipaddr"); |
| if (opt_val && tb_router) { |
| blobmsg_add_string(&router_buf, "lan_ip", opt_val); |
| } |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "netmask"); |
| if (opt_val && tb_router) { |
| blobmsg_add_string(&router_buf, "lan_netmask", opt_val); |
| } |
| |
| break; |
| } |
| } |
| } |
| } |
| |
| if (tb_router) { |
| blobmsg_close_table(&router_buf, tb_router); |
| } |
| free_router_uci_ctx(); |
| ubus_send_reply(ctx, req, router_buf.head); |
| blob_buf_free(&router_buf); |
| ROUTER_DBG("leave"); |
| return 0; |
| } |
| |
| /*set router lan ip*/ |
| /*================================================ |
| <router> |
| <lan_ip/> |
| </router> |
| Note : the dhcp settings is only included in config 'dhcp' 'lan' |
| ================================================*/ |
| enum { |
| LAN_IP |
| }; |
| static const struct blobmsg_policy router_setting_pol[] = { |
| [LAN_IP] = { |
| .name = "lan_ip", |
| .type = BLOBMSG_TYPE_STRING, |
| }, |
| }; |
| |
| struct up_ifa_name *g_head_if_name; |
| static int router_restart_lan(struct up_ifa_name *head) |
| { |
| struct up_ifa_name *p_if_name = head; |
| struct up_ifa_name *next_if_name = NULL; |
| char cmd_buf[MAX_CMD_BUF_SIZE] = { 0 }; |
| |
| /*should down ccinet interface first */ |
| while (p_if_name) { |
| memset(cmd_buf, 0, MAX_CMD_BUF_SIZE); |
| snprintf(cmd_buf, MAX_CMD_BUF_SIZE - 1, "/bin/ubus call network.interface.%s down", p_if_name->name); |
| ROUTER_DBG("cmd:%s", cmd_buf); |
| router_system(cmd_buf); |
| p_if_name = p_if_name->next; |
| } |
| router_system("/etc/init.d/network reload"); |
| p_if_name = head; |
| while (p_if_name) { |
| memset(cmd_buf, 0, MAX_CMD_BUF_SIZE); |
| snprintf(cmd_buf, MAX_CMD_BUF_SIZE - 1, "/bin/ubus call network.interface.%s up", p_if_name->name); |
| ROUTER_DBG("cmd:%s", cmd_buf); |
| router_system(cmd_buf); |
| p_if_name = p_if_name->next; |
| } |
| /*free buffer anyway*/ |
| p_if_name = head; |
| while(p_if_name) { |
| next_if_name = p_if_name->next; |
| if (p_if_name->name) |
| free(p_if_name->name); |
| free(p_if_name); |
| p_if_name = next_if_name; |
| } |
| |
| return 0; |
| } |
| |
| int router_set_lan_ip_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| void *tb_router = NULL; |
| struct uci_ptr ptr; |
| struct blob_attr *router_setting[ARRAY_SIZE(router_setting_pol)]; |
| int ret_val = 0; |
| const char *ip_value = NULL, *ip6_value = NULL; |
| struct up_ifa_name *p_if_name = NULL, *head_if_name = NULL, *next_if_name = NULL; |
| |
| |
| UNUSESET(obj); |
| UNUSESET(method); |
| |
| if (blobmsg_parse |
| (router_setting_pol, ARRAY_SIZE(router_setting_pol), router_setting, blob_data(msg), blob_len(msg)) != 0) { |
| ROUTER_ERR("Parse failed\n"); |
| ret_val = UBUS_STATUS_INVALID_ARGUMENT; |
| goto EXIT; |
| } |
| if (!router_setting[LAN_IP]) { |
| ROUTER_ERR("NO DATA"); |
| ret_val = UBUS_STATUS_INVALID_ARGUMENT; |
| goto EXIT; |
| } |
| /*load /etc/config/network */ |
| local_ctx = (struct uci_context *)uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, NW_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| if (!p) { |
| uci_load(local_ctx, NW_PACK, &p); |
| } |
| if (p) { |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (strcmp(uci_sec->type, "interface") == 0) { |
| if (uci_sec->e.name && strcmp(uci_sec->e.name, "lan") == 0) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec; |
| ptr.option = "ipaddr"; |
| ptr.value = blobmsg_get_string(router_setting[LAN_IP]); |
| uci_set(local_ctx, &ptr); |
| break; |
| } else if (uci_sec->e.name && strstr(uci_sec->e.name, "wan") != NULL) { |
| ip_value = uci_lookup_option_string(local_ctx, uci_sec, "ipaddr"); |
| ip6_value = uci_lookup_option_string(local_ctx, uci_sec, "ip6addr"); |
| if (ip_value || ip6_value) { |
| p_if_name = (struct up_ifa_name *)malloc(sizeof(struct up_ifa_name)); |
| if (!p_if_name) { |
| ROUTER_ERR("malloc size %d failed!\n", sizeof(struct up_ifa_name)); |
| ret_val = UBUS_STATUS_UNKNOWN_ERROR; |
| goto EXIT; |
| } |
| memset(p_if_name, 0, sizeof(struct up_ifa_name)); |
| if (!head_if_name) { |
| head_if_name = p_if_name; |
| g_head_if_name = head_if_name; |
| } |
| p_if_name->name = strdup(uci_sec->e.name); |
| p_if_name = p_if_name->next; |
| } |
| } |
| |
| } |
| } |
| } |
| |
| EXIT: |
| blobmsg_buf_init(&router_buf); |
| tb_router = blobmsg_open_table(&router_buf, "router"); |
| if (tb_router) { |
| if (ret_val == 0) { |
| blobmsg_add_string(&router_buf, "setting_response", "OK"); |
| if (p) { |
| uci_commit(local_ctx, &p, false); |
| } |
| } else { |
| blobmsg_add_string(&router_buf, "setting_response", "ERROR"); |
| } |
| blobmsg_close_table(&router_buf, tb_router); |
| } |
| ubus_send_reply(ctx, req, router_buf.head); |
| blob_buf_free(&router_buf); |
| free_router_uci_ctx(); |
| #if 0 |
| if (ret_val == 0) { |
| /*should down ccinet interface first */ |
| p_if_name = head_if_name; |
| while (p_if_name) { |
| memset(cmd_buf, 0, MAX_CMD_BUF_SIZE); |
| snprintf(cmd_buf, MAX_CMD_BUF_SIZE - 1, "/bin/ubus call network.interface.%s down", p_if_name->name); |
| ROUTER_DBG("cmd:%s", cmd_buf); |
| router_system(cmd_buf); |
| p_if_name = p_if_name->next; |
| } |
| router_system("/etc/init.d/network reload"); |
| p_if_name = head_if_name; |
| while (p_if_name) { |
| memset(cmd_buf, 0, MAX_CMD_BUF_SIZE); |
| snprintf(cmd_buf, MAX_CMD_BUF_SIZE - 1, "/bin/ubus call network.interface.%s up", p_if_name->name); |
| ROUTER_DBG("cmd:%s", cmd_buf); |
| router_system(cmd_buf); |
| p_if_name = p_if_name->next; |
| } |
| /*free buffer anyway*/ |
| p_if_name = head_if_name; |
| while(p_if_name) { |
| next_if_name = p_if_name; |
| if (p_if_name->name) |
| free(p_if_name->name); |
| free(p_if_name); |
| p_if_name = next_if_name; |
| } |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| /*get DHCP settings*/ |
| /*================================================ |
| <dhcp> |
| <disable/> |
| <start/> |
| <limit/> |
| <leasetime/> |
| <option_gateway/> |
| <option_dns/> |
| </dhcp> |
| Note : the dhcp settings is only included in config 'dhcp' 'lan' |
| ================================================*/ |
| int dhcp_get_info_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| struct uci_option *list_opt = NULL; |
| struct uci_option *uci_opt = NULL; |
| struct uci_element *e_list = NULL; |
| |
| const char *opt_val = NULL; |
| void *tb_dhcp = NULL; |
| int opt_type = 0; |
| int gateway_find = 0; |
| int dns_find = 0; |
| |
| ROUTER_DBG("enter"); |
| UNUSESET(obj); |
| UNUSESET(method); |
| UNUSESET(msg); |
| |
| /*load /etc/config/dhcp */ |
| local_ctx = (struct uci_context *)uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| ROUTER_DBG("get uci ctx OK\r\n"); |
| |
| blobmsg_buf_init(&router_buf); |
| tb_dhcp = blobmsg_open_table(&router_buf, "dhcp"); |
| |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, DHCP_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| if (!p) { |
| uci_load(local_ctx, DHCP_PACK, &p); |
| } |
| |
| if (p) { |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (strcmp(uci_sec->type, "dhcp") == 0) { |
| ROUTER_DBG("got one dhcp section"); |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "interface"); |
| if (opt_val && (strcmp(opt_val, "lan") == 0)) { |
| ROUTER_DBG("got the dhcp pool settings"); |
| /*disabled */ |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "ignore"); |
| if (opt_val && (strcmp(opt_val, "1") == 0)) { |
| ROUTER_DBG("DHCP is disabled"); |
| blobmsg_add_string(&router_buf, "disabled", "1"); |
| } else { |
| blobmsg_add_string(&router_buf, "disabled", "0"); |
| } |
| /*start addr */ |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "start"); |
| if (opt_val) { |
| blobmsg_add_string(&router_buf, "start", opt_val); |
| } |
| /*limit */ |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "limit"); |
| if (opt_val) { |
| blobmsg_add_string(&router_buf, "limit", opt_val); |
| } |
| /*leasetime */ |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "leasetime"); |
| if (opt_val) { |
| blobmsg_add_string(&router_buf, "leasetime", opt_val); |
| } |
| |
| list_opt = uci_lookup_option(local_ctx, uci_sec, "dhcp_option"); |
| if (list_opt && list_opt->type == UCI_TYPE_LIST) { |
| uci_foreach_element(&list_opt->v.list, e_list) { |
| uci_opt = uci_to_option(e_list); |
| if (uci_opt->e.name) { |
| ROUTER_DBG("got one list value: %s", uci_opt->e.name); |
| parse_dhcp_option_str(uci_opt->e.name, &router_buf, &opt_type); |
| switch (opt_type) { |
| case OPT_GATEWAY_TYPE: |
| gateway_find = 1; |
| break; |
| case OPT_DNS_TYPE: |
| dns_find = 1; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| } |
| |
| if (gateway_find == 0) |
| blobmsg_add_string(&router_buf, "option_gateway", "disable"); |
| |
| if (dns_find == 0) |
| blobmsg_add_string(&router_buf, "option_dns", "disable,disable"); |
| |
| //blobmsg_add_string(&router_buf, "option_gateway", "disable"); |
| //blobmsg_add_string(&router_buf, "option_dns", "disable,disable"); |
| } |
| break; |
| } |
| } |
| } |
| |
| if (tb_dhcp) { |
| blobmsg_close_table(&router_buf, tb_dhcp); |
| } |
| free_router_uci_ctx(); |
| ubus_send_reply(ctx, req, router_buf.head); |
| blob_buf_free(&router_buf); |
| ROUTER_DBG("leave"); |
| return 0; |
| } |
| |
| /*================================================ |
| <dhcp> |
| <disable/> |
| <start/> |
| <limit/> |
| <leasetime/> |
| <option_gateway/> |
| <option_dns/> |
| <lanip_changed/> |
| </dhcp> |
| Note : the dhcp settings is only included in config 'dhcp' 'lan' |
| ================================================*/ |
| |
| int dhcp_set_info_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| const char *opt_val = NULL; |
| void *tb_dhcp = NULL; |
| struct uci_ptr ptr; |
| struct blob_attr *dhcp_setting[ARRAY_SIZE(dhcp_setting_pol)]; |
| int ret_val = 0; |
| int lanip_changed = 0; |
| |
| UNUSESET(obj); |
| UNUSESET(method); |
| |
| if (blobmsg_parse(dhcp_setting_pol, ARRAY_SIZE(dhcp_setting_pol), dhcp_setting, blob_data(msg), blob_len(msg)) |
| != 0) { |
| ROUTER_ERR("Parse failed\n"); |
| ret_val = UBUS_STATUS_INVALID_ARGUMENT; |
| goto EXIT; |
| } |
| /*load /etc/config/dhcp */ |
| local_ctx = (struct uci_context *)uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, DHCP_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| if (!p) { |
| uci_load(local_ctx, DHCP_PACK, &p); |
| } |
| if (p) { |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (strcmp(uci_sec->type, "dhcp") == 0) { |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "interface"); |
| if (opt_val && (strcmp(opt_val, "lan") == 0)) { |
| ROUTER_DBG("got the lan device settings"); |
| if (dhcp_setting[DHCP_DISABLED]) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec, ptr.option = "ignore"; |
| ptr.value = blobmsg_get_string(dhcp_setting[DHCP_DISABLED]); |
| uci_set(local_ctx, &ptr); |
| } |
| if (dhcp_setting[DHCP_START]) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec, ptr.option = "start"; |
| ptr.value = blobmsg_get_string(dhcp_setting[DHCP_START]); |
| uci_set(local_ctx, &ptr); |
| } |
| if (dhcp_setting[DHCP_LIMIT]) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec, ptr.option = "limit"; |
| ptr.value = blobmsg_get_string(dhcp_setting[DHCP_LIMIT]); |
| uci_set(local_ctx, &ptr); |
| } |
| if (dhcp_setting[DHCP_LEASETIME]) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec, ptr.option = "leasetime"; |
| ptr.value = blobmsg_get_string(dhcp_setting[DHCP_LEASETIME]); |
| uci_set(local_ctx, &ptr); |
| } |
| if (dhcp_setting[DHCP_GATEWAY]) { |
| ROUTER_DBG("got the option_gateway value %s", blobmsg_get_string(dhcp_setting[DHCP_GATEWAY])); |
| set_dhcp_option_value(local_ctx, p, uci_sec, OPT_GATEWAY_TYPE, blobmsg_get_string(dhcp_setting[DHCP_GATEWAY])); |
| } |
| |
| if (dhcp_setting[DHCP_DNS]) { |
| ROUTER_DBG("got the option_dns %s", blobmsg_get_string(dhcp_setting[DHCP_DNS])); |
| set_dhcp_option_value(local_ctx, p, uci_sec, OPT_DNS_TYPE, blobmsg_get_string(dhcp_setting[DHCP_DNS])); |
| } |
| ROUTER_DBG("dhcp_setting_pol size %d", ARRAY_SIZE(dhcp_setting_pol)); |
| if (dhcp_setting[DHCP_LANIP_CHANGED]) { |
| ROUTER_DBG("got the lanip_changed %s", blobmsg_get_string(dhcp_setting[DHCP_LANIP_CHANGED])); |
| lanip_changed = blobmsg_get_string(dhcp_setting[DHCP_LANIP_CHANGED]); |
| } |
| } |
| } |
| } |
| } |
| |
| EXIT: |
| blobmsg_buf_init(&router_buf); |
| tb_dhcp = blobmsg_open_table(&router_buf, "dhcp"); |
| if (tb_dhcp) { |
| if (ret_val == 0) { |
| blobmsg_add_string(&router_buf, "setting_response", "OK"); |
| if (p) { |
| uci_commit(local_ctx, &p, false); |
| } |
| } else { |
| blobmsg_add_string(&router_buf, "setting_response", "ERROR"); |
| } |
| blobmsg_close_table(&router_buf, tb_dhcp); |
| } |
| ubus_send_reply(ctx, req, router_buf.head); |
| blob_buf_free(&router_buf); |
| free_router_uci_ctx(); |
| if (ret_val == 0) { |
| if (lanip_changed) { |
| router_restart_lan(g_head_if_name); |
| g_head_if_name = NULL; |
| sleep(1); |
| } |
| if (lanip_changed != 2) |
| router_system("/etc/init.d/dnsmasq reload"); |
| } |
| |
| return 0; |
| } |
| |
| /*================================================ |
| <dhcp> |
| <fixed_ip_list> |
| <entry_index> |
| <ip/> |
| <mac/> |
| <name/> |
| </entry_index> |
| ... |
| </fixed_ip_list> |
| </firewall> |
| ================================================*/ |
| int dhcp_get_fixed_ip_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| const char *opt_val = NULL; |
| void *tb_dhcp = NULL; |
| void *tb_fixed_ip_list = NULL; |
| void *tb_entry = NULL; |
| int entry_index = 1; |
| char entry_buf[16]; |
| |
| ROUTER_DBG("enter"); |
| UNUSESET(obj); |
| UNUSESET(method); |
| UNUSESET(msg); |
| |
| /*load /etc/config/dhcp */ |
| local_ctx = (struct uci_context *)uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| ROUTER_DBG("get uci ctx OK\r\n"); |
| |
| blobmsg_buf_init(&router_buf); |
| tb_dhcp = blobmsg_open_table(&router_buf, "dhcp"); |
| if (!tb_dhcp) { |
| assert(0); |
| } |
| tb_fixed_ip_list = blobmsg_open_table(&router_buf, "fixed_ip_list"); |
| if (!tb_fixed_ip_list) { |
| assert(0); |
| } |
| |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, DHCP_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| if (!p) { |
| uci_load(local_ctx, DHCP_PACK, &p); |
| } |
| |
| if (p) { |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (strcmp(uci_sec->type, "host") == 0) { |
| ROUTER_DBG("got one host section"); |
| memset(entry_buf, 0, sizeof(entry_buf)); |
| snprintf(entry_buf, sizeof(entry_buf), "entry_%d", entry_index++); |
| ROUTER_DBG("entry_buf : %s", entry_buf); |
| tb_entry = blobmsg_open_table(&router_buf, entry_buf); |
| if (tb_entry) { |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "ip"); |
| if (opt_val) { |
| ROUTER_DBG("ip:%s", opt_val); |
| blobmsg_add_string(&router_buf, "ip", opt_val); |
| } |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "mac"); |
| if (opt_val) { |
| ROUTER_DBG("mac:%s", opt_val); |
| blobmsg_add_string(&router_buf, "mac", opt_val); |
| } |
| opt_val = uci_lookup_option_string(local_ctx, uci_sec, "name"); |
| if (opt_val) { |
| ROUTER_DBG("name:%s", opt_val); |
| |
| blobmsg_add_string(&router_buf, "name", opt_val); |
| } |
| |
| blobmsg_close_table(&router_buf, tb_entry); |
| } |
| } |
| } |
| } |
| if (tb_fixed_ip_list) { |
| ROUTER_DBG("close tb_fixed_ip_list"); |
| blobmsg_close_table(&router_buf, tb_fixed_ip_list); |
| } |
| if (tb_dhcp) { |
| ROUTER_DBG("close tb_dhcp"); |
| blobmsg_close_table(&router_buf, tb_dhcp); |
| } |
| free_router_uci_ctx(); |
| ubus_send_reply(ctx, req, router_buf.head); |
| blob_buf_free(&router_buf); |
| return 0; |
| } |
| |
| enum { |
| ADD_FIXED_IP_ENTRY, |
| EDIT_FIXED_IP_ENTRY, |
| }; |
| enum { |
| FIXED_IP_ADDR, |
| FIXED_IP_MAC, |
| FIXED_IP_NAME, |
| }; |
| static const struct blobmsg_policy dhcp_fixed_ip_pol[] = { |
| [FIXED_IP_ADDR] = { |
| .name = "ip", |
| .type = BLOBMSG_TYPE_STRING, |
| }, |
| [FIXED_IP_MAC] = { |
| .name = "mac", |
| .type = BLOBMSG_TYPE_STRING, |
| }, |
| [FIXED_IP_NAME] = { |
| .name = "name", |
| .type = BLOBMSG_TYPE_STRING, |
| }, |
| }; |
| |
| static int dhcp_set_fixed_ip_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg, int type) |
| { |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| struct uci_ptr ptr; |
| struct blob_attr *attr_head = NULL; |
| struct blob_attr *attr; |
| struct blobmsg_hdr *hdr; |
| struct blob_attr *entry_attr[ARRAY_SIZE(dhcp_fixed_ip_pol)]; |
| struct blob_attr *dhcp_setting[ARRAY_SIZE(dhcp_setting_pol)]; |
| int attr_len = 0; |
| int edit_index = 0; |
| int index = 0; |
| int ret_val = 0; |
| void *tb_dhcp = NULL; |
| |
| UNUSESET(obj); |
| UNUSESET(method); |
| |
| if (blobmsg_parse(dhcp_setting_pol, ARRAY_SIZE(dhcp_setting_pol), dhcp_setting, blob_data(msg), blob_len(msg)) |
| != 0) { |
| ROUTER_ERR("Parse failed\n"); |
| ret_val = UBUS_STATUS_INVALID_ARGUMENT; |
| goto EXIT; |
| } |
| if (!dhcp_setting[DHCP_FIXED_IP_LIST]) { |
| ROUTER_ERR("NO DATA"); |
| ret_val = UBUS_STATUS_INVALID_ARGUMENT; |
| goto EXIT; |
| } |
| /*load /etc/config/dhcp */ |
| local_ctx = (struct uci_context *)uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, DHCP_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| if (!p) { |
| uci_load(local_ctx, DHCP_PACK, &p); |
| } |
| |
| if (dhcp_setting[DHCP_FIXED_IP_LIST]) { |
| ROUTER_DBG("add new dns filter"); |
| attr_head = blobmsg_data(dhcp_setting[DHCP_FIXED_IP_LIST]); |
| attr_len = blobmsg_data_len(dhcp_setting[DHCP_FIXED_IP_LIST]); |
| __blob_for_each_attr(attr, attr_head, attr_len) { |
| hdr = blob_data(attr); |
| /*name as entry_index,entry_1, entry_2,eg. */ |
| if (hdr->name) { |
| ROUTER_DBG("got one entry_index -- %s", hdr->name); |
| } |
| if (!strstr((char *)hdr->name, "entry")) { |
| continue; |
| } |
| if (type == EDIT_FIXED_IP_ENTRY) { |
| if (sscanf((char *)hdr->name, "%*5s_%d", &edit_index) == 1) { |
| ROUTER_DBG("get edit index -- %d", edit_index); |
| } else { |
| ROUTER_ERR("get edit index fail"); |
| ret_val = 1; |
| goto EXIT; |
| } |
| } |
| /*type should be table */ |
| if (blob_id(attr) != BLOBMSG_TYPE_TABLE) { |
| continue; |
| } |
| ROUTER_DBG("GOT ONE NEW ENTRY"); |
| if (blobmsg_parse |
| (dhcp_fixed_ip_pol, ARRAY_SIZE(dhcp_fixed_ip_pol), entry_attr, blobmsg_data(attr), |
| blobmsg_data_len(attr)) == 0) { |
| if (type == ADD_FIXED_IP_ENTRY) { |
| /*add one section with type :host */ |
| uci_add_section(local_ctx, p, "host", &uci_sec); |
| } else if (type == EDIT_FIXED_IP_ENTRY) { |
| index = 0; |
| /*find the rule */ |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (!strcmp(uci_sec->type, "host")) { |
| index++; |
| if (index == edit_index) { |
| ROUTER_DBG("find edit index %d", index); |
| break; |
| } |
| } |
| } |
| } |
| if (uci_sec) { |
| ROUTER_DBG("uci_sec OK!"); |
| if (entry_attr[FIXED_IP_ADDR]) { |
| ROUTER_DBG("FIXED_IP_ADDR is %s", |
| blobmsg_get_string(entry_attr[FIXED_IP_ADDR])); |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec; |
| ptr.option = "ip"; |
| ptr.value = blobmsg_get_string(entry_attr[FIXED_IP_ADDR]); |
| uci_set(local_ctx, &ptr); |
| } |
| if (entry_attr[FIXED_IP_MAC]) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec; |
| ptr.option = "mac"; |
| ptr.value = blobmsg_get_string(entry_attr[FIXED_IP_MAC]); |
| uci_set(local_ctx, &ptr); |
| } |
| if (entry_attr[FIXED_IP_NAME]) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = uci_sec; |
| ptr.option = "name"; |
| ptr.value = blobmsg_get_string(entry_attr[FIXED_IP_NAME]); |
| uci_set(local_ctx, &ptr); |
| } |
| } else { |
| ROUTER_DBG("uci_sec is NULL"); |
| } |
| } |
| } |
| } |
| |
| EXIT: |
| blobmsg_buf_init(&router_buf); |
| tb_dhcp = blobmsg_open_table(&router_buf, "dhcp"); |
| if (tb_dhcp) { |
| if (ret_val == 0) { |
| blobmsg_add_string(&router_buf, "setting_response", "OK"); |
| if (p) { |
| uci_commit(local_ctx, &p, false); |
| } |
| } else { |
| blobmsg_add_string(&router_buf, "setting_response", "ERROR"); |
| } |
| blobmsg_close_table(&router_buf, tb_dhcp); |
| } |
| ubus_send_reply(ctx, req, router_buf.head); |
| blob_buf_free(&router_buf); |
| free_router_uci_ctx(); |
| if (ret_val == 0) { |
| router_system("/etc/init.d/dnsmasq reload"); |
| } |
| |
| return 0; |
| } |
| |
| int dhcp_add_fixed_ip_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| return dhcp_set_fixed_ip_cb(ctx, obj, req, method, msg, ADD_FIXED_IP_ENTRY); |
| } |
| |
| int dhcp_edit_fixed_ip_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| return dhcp_set_fixed_ip_cb(ctx, obj, req, method, msg, EDIT_FIXED_IP_ENTRY); |
| } |
| |
| /*================================================ |
| <dhcp> |
| <del_fixed_ip_index> |
| </dhcp> |
| seperate by ',' |
| ================================================*/ |
| int dhcp_delete_fixed_ip_cb(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, struct blob_attr *msg) |
| { |
| struct uci_context *local_ctx = NULL; |
| struct uci_element *e = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *uci_sec = NULL; |
| void *tb_dhcp = NULL; |
| struct uci_ptr ptr; |
| int ret_val = 0; |
| struct uci_section **delete_uci_array = NULL; |
| int delete_num = 0; |
| char *begin = NULL; |
| char *end = NULL; |
| int *del_index_array = NULL; |
| char tmp_buf[5] = { 0 }; |
| int cur_index = 0; |
| int tmp_index = 0; |
| struct blob_attr *dhcp_setting_attr[ARRAY_SIZE(dhcp_setting_pol)]; |
| ROUTER_DBG("enter"); |
| |
| UNUSESET(obj); |
| UNUSESET(method); |
| |
| if (blobmsg_parse |
| (dhcp_setting_pol, ARRAY_SIZE(dhcp_setting_pol), dhcp_setting_attr, blob_data(msg), blob_len(msg)) != 0) { |
| ROUTER_ERR("Parse failed\n"); |
| ret_val = UBUS_STATUS_INVALID_ARGUMENT; |
| goto EXIT; |
| } |
| if (!dhcp_setting_attr[DHCP_DEL_FIXED_IP_INDEX]) { |
| ret_val = UBUS_STATUS_INVALID_ARGUMENT; |
| goto EXIT; |
| } |
| /*load /etc/config/dhcp */ |
| local_ctx = uci_router_ctx_get(); |
| if (!local_ctx) { |
| assert(0); |
| } |
| ROUTER_DBG("get uci ctx OK\r\n"); |
| |
| { |
| uci_foreach_element(&local_ctx->root, e) { |
| if (strcmp(e->name, DHCP_PACK) != 0) |
| continue; |
| p = uci_to_package(e); //have found |
| } |
| } |
| if (!p) { |
| uci_load(local_ctx, DHCP_PACK, &p); |
| } |
| if (!p) { |
| ret_val = UBUS_STATUS_NO_DATA; |
| goto EXIT; |
| } |
| ROUTER_DBG("delete index is %s", blobmsg_get_string(dhcp_setting_attr[DHCP_DEL_FIXED_IP_INDEX])); |
| if (dhcp_setting_attr[DHCP_DEL_FIXED_IP_INDEX]) { |
| begin = blobmsg_get_string(dhcp_setting_attr[DHCP_DEL_FIXED_IP_INDEX]); |
| |
| /*to get the number of delete index */ |
| while ((begin = strchr(begin, ','))) { |
| delete_num += 1; |
| begin += 1; |
| } |
| ROUTER_DBG(" delete total is %d", delete_num); |
| if (delete_num == 0) { |
| ret_val = 2; |
| goto EXIT; |
| } |
| /*malloc memory */ |
| delete_uci_array = (struct uci_section **)malloc(delete_num * sizeof(struct uci_section *)); |
| memset(delete_uci_array, 0, delete_num * sizeof(struct uci_section *)); |
| del_index_array = (int *)malloc(delete_num * sizeof(int)); |
| memset(del_index_array, 0, delete_num * sizeof(int)); |
| |
| /*get the index, storing into del_index_array */ |
| cur_index = 0; |
| begin = blobmsg_get_string(dhcp_setting_attr[DHCP_DEL_FIXED_IP_INDEX]); |
| while ((end = strchr(begin, ','))) { |
| memset(tmp_buf, 0, 5); |
| if (((end - begin) < 5)){ |
| memcpy(tmp_buf, begin, end - begin); |
| } else { |
| continue; |
| } |
| if (cur_index > delete_num) { |
| break; |
| } |
| del_index_array[cur_index++] = atoi(tmp_buf); |
| begin = end + 1; |
| } |
| /*Print the delete index */ |
| for (tmp_index = 0; tmp_index < delete_num; tmp_index++) { |
| ROUTER_DBG("delete index %d", del_index_array[tmp_index]); |
| } |
| /*travel the sections ,and storing the deleting uci_sec to delete_uci_array */ |
| cur_index = 0; |
| uci_foreach_element(&p->sections, e) { |
| uci_sec = uci_to_section(e); |
| if (strcmp(uci_sec->type, "host") == 0) { |
| cur_index++; |
| for (tmp_index = 0; tmp_index < delete_num; tmp_index++) { |
| if (del_index_array[tmp_index] == 0) { |
| continue; |
| } |
| if (cur_index == del_index_array[tmp_index]) { |
| ROUTER_DBG("find uci_sec with index %d", cur_index); |
| delete_uci_array[tmp_index] = uci_sec; |
| break; |
| } |
| } |
| } |
| } |
| |
| } |
| /*delete the section */ |
| for (tmp_index = 0; tmp_index < delete_num; tmp_index++) { |
| memset(&ptr, 0, sizeof(struct uci_ptr)); |
| ptr.p = p; |
| ptr.s = delete_uci_array[tmp_index]; |
| uci_delete(local_ctx, &ptr); |
| } |
| |
| EXIT: |
| if (del_index_array) { |
| free(del_index_array); |
| del_index_array = NULL; |
| } |
| if (delete_uci_array) { |
| free(delete_uci_array); |
| delete_uci_array = NULL; |
| } |
| blobmsg_buf_init(&router_buf); |
| tb_dhcp = blobmsg_open_table(&router_buf, "firewall"); |
| if (ret_val == 0) { |
| blobmsg_add_string(&router_buf, "setting_response", "OK"); |
| if (p) { |
| uci_commit(local_ctx, &p, false); |
| } |
| } else { |
| blobmsg_add_string(&router_buf, "setting_response", "ERROR"); |
| } |
| blobmsg_close_table(&router_buf, tb_dhcp); |
| ubus_send_reply(ctx, req, router_buf.head); |
| blob_buf_free(&router_buf); |
| free_router_uci_ctx(); |
| ROUTER_DBG("leave"); |
| if (ret_val == 0) { |
| router_system("/etc/init.d/dnsmasq reload"); |
| } |
| |
| return ret_val; |
| } |