diff --git a/src/Makefile b/src/Makefile index a60218dd97c14267131ee2ed9edbf449c10603ed..60f5d0d6090dcbf3c03e47648a8af12a50cb7059 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,6 +7,7 @@ LIBNETMNGROBJS := net_plugin.o \ routing.o \ ppp.o \ routeradvertisement.o \ + ipv6rd.o \ common.o LIBIFACESTACKOBJS := interfacestack.o diff --git a/src/ip.c b/src/ip.c index 2be80d57ffbdabb9daf271e5ca969eb62003b028..2d19cc2fbdf83e2182f9a15759240dac995126e3 100644 --- a/src/ip.c +++ b/src/ip.c @@ -2399,7 +2399,7 @@ DMLEAF tIPInterfaceIPv4AddressParams[] = { {"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv4Address_Enable, set_IPInterfaceIPv4Address_Enable, BBFDM_BOTH}, {"Status", &DMREAD, DMT_STRING, get_IPInterfaceIPv4Address_Status, NULL, BBFDM_BOTH}, {"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceIPv4Address_Alias, set_IPInterfaceIPv4Address_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, -{"IPAddress", &DMWRITE, DMT_STRING, get_IPInterfaceIPv4Address_IPAddress, set_IPInterfaceIPv4Address_IPAddress, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"IPAddress", &DMWRITE, DMT_STRING, get_IPInterfaceIPv4Address_IPAddress, set_IPInterfaceIPv4Address_IPAddress, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER}, {"SubnetMask", &DMWRITE, DMT_STRING, get_IPInterfaceIPv4Address_SubnetMask, set_IPInterfaceIPv4Address_SubnetMask, BBFDM_BOTH, DM_FLAG_UNIQUE}, {"AddressingType", &DMREAD, DMT_STRING, get_IPInterfaceIPv4Address_AddressingType, NULL, BBFDM_BOTH}, {0} diff --git a/src/ipv6rd.c b/src/ipv6rd.c new file mode 100644 index 0000000000000000000000000000000000000000..e9ad296b9942e0f6f3c764a430fccc707d1a4188 --- /dev/null +++ b/src/ipv6rd.c @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2024 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu> + */ + +#include "ipv6rd.h" + +#define DEFAULT_SEC_NAME "wan6rd" + +/************************************************************* +* ENTRY METHOD +**************************************************************/ +static int browseIPv6rdInterfaceSettingInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct dm_data *curr_data = NULL; + LIST_HEAD(dup_list); + char *inst = NULL; + + // if 6rd sections are present in uci then handle them + synchronize_specific_config_sections_with_dmmap_eq("network", "interface", "dmmap_ipv6rd", "proto", "6rd", &dup_list); + list_for_each_entry(curr_data, &dup_list, list) { + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "ipv6rd_intf_instance", "ipv6rd_intf_alias"); + + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)curr_data, inst) == DM_STOP) + break; + } + + free_dmmap_config_dup_list(&dup_list); + + // no 6rd section was found + // we still present one 6rd object with empty values + // and if the any parameter is set then section will + // be created + if (!inst) { + struct dm_data data = {0}; + struct uci_section *dmmap_sec = NULL; + + dmuci_add_section_bbfdm("dmmap_ipv6rd", "interface", &dmmap_sec); + dmuci_set_value_by_section(dmmap_sec, "section_name", DEFAULT_SEC_NAME); + dmuci_set_value_by_section(dmmap_sec, "ipv6rd_intf_instance", "1"); + dmuci_set_value_by_section(dmmap_sec, "ipv6rd_intf_alias", "cpe-1"); + + data.dmmap_section = dmmap_sec; + + inst = handle_instance(dmctx, parent_node, data.dmmap_section, "ipv6rd_intf_instance", "ipv6rd_intf_alias"); + DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&data, inst); + } + + return 0; +} + +/************************************************************* +* GET & SET PARAM +**************************************************************/ +static int get_IPv6rd_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + // no way to disable ipv6rd for now, always enabled + *value = "1"; + return 0; +} + +static int set_IPv6rd_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + // no way to disable ipv6rd for now, always enabled + break; + } + return 0; +} + +static int get_IPv6rd_InterfaceSettingNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + int cnt = get_number_of_entries(ctx, data, instance, browseIPv6rdInterfaceSettingInst); + dmasprintf(value, "%d", cnt); + return 0; +} + +static int get_IPv6rdInterfaceSetting_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "0"; + + if (((struct dm_data *)data)->config_section == NULL) + return 0; + + char *disabled = NULL; + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", &disabled); + + if (DM_STRCMP(disabled, "1") != 0) + *value = "1"; + + return 0; +} + +static void check_and_add_6rd_section(void **data) +{ + struct dm_data *curr_data = *((struct dm_data **)data); + + if (curr_data->config_section == NULL) { + struct uci_section *s = NULL; + + dmuci_add_section("network", "interface", &s); + dmuci_rename_section_by_section(s, DEFAULT_SEC_NAME); + dmuci_set_value_by_section(s, "proto", "6rd"); + dmuci_set_value_by_section(s, "disabled", "1"); + + // for return value + curr_data->config_section = s; + } +} + +static int set_IPv6rdInterfaceSetting_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + check_and_add_6rd_section(&data); + + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1"); + break; + } + return 0; +} + +static int get_IPv6rdInterfaceSetting_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + get_IPv6rdInterfaceSetting_Enable(refparam, ctx, data, instance, value); + *value = ((*value)[0] == '1') ? "Enabled" : "Disabled"; + return 0; +} + +static int get_IPv6rdInterfaceSetting_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv6rd_intf_alias", instance, value); +} + +static int set_IPv6rdInterfaceSetting_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + check_and_add_6rd_section(&data); + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "ipv6rd_intf_alias", instance, value); +} + +static int get_IPv6rdInterfaceSetting_BorderRelayIPv4Addresses(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (((struct dm_data *)data)->config_section == NULL) { + *value = ""; + return 0; + } + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "peeraddr", value); + return 0; +} + +static int set_IPv6rdInterfaceSetting_BorderRelayIPv4Addresses(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + // only single IPv4 address is allowed in openwrt + if (bbfdm_validate_string(ctx, value, -1, 15, NULL, IPv4Address)) + return FAULT_9007; + break; + case VALUESET: + check_and_add_6rd_section(&data); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "peeraddr", value); + break; + } + return 0; +} + +static int get_IPv6rdInterfaceSetting_AllTrafficToBorderRelay(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (((struct dm_data *)data)->config_section == NULL) { + *value = ""; + return 0; + } + // this is always true in openwrt + *value = "1"; + return 0; +} + +static int set_IPv6rdInterfaceSetting_AllTrafficToBorderRelay(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + // this is always true in openwrt + // if logic is added in future, remember to use check_and_add_6rd_section + break; + } + return 0; +} + +static int get_IPv6rdInterfaceSetting_SPIPv6Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ""; + + if (((struct dm_data *)data)->config_section == NULL) + return 0; + + char *ip6prefix = NULL, *ip6prefixlen = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ip6prefix", &ip6prefix); + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ip6prefixlen", &ip6prefixlen); + + if (DM_STRLEN(ip6prefix) && DM_STRLEN(ip6prefixlen)) + dmasprintf(value, "%s/%s", ip6prefix, ip6prefixlen); + + return 0; +} + +static int set_IPv6rdInterfaceSetting_SPIPv6Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, -1, NULL, IPv6Prefix)) + return FAULT_9007; + break; + case VALUESET: + check_and_add_6rd_section(&data); + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "prefix", value); + // separate the prefix and prefix len + char *slash = DM_STRCHR(value, '/'); + if (!slash) + return FAULT_9002; + + // terminate prefix where slash was present + *slash = '\0'; + slash++; + + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ip6prefix", value); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ip6prefixlen", slash); + break; + } + return 0; +} + +static int get_IPv6rdInterfaceSetting_IPv4MaskLength(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (((struct dm_data *)data)->config_section == NULL) { + *value = ""; + return 0; + } + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ip4prefixlen", value); + return 0; +} + +static int set_IPv6rdInterfaceSetting_IPv4MaskLength(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","32"}}, 1)) + return FAULT_9007; + break; + case VALUESET: + check_and_add_6rd_section(&data); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ip4prefixlen", value); + break; + } + return 0; +} + +static int get_IPv6rdInterfaceSetting_AddressSource(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (((struct dm_data *)data)->config_section == NULL) { + *value = ""; + return 0; + } + + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ipv4path", value); + + if (!value || (*value)[0] == '\0') { + char *ipaddr = NULL; + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ipaddr", &ipaddr); + + _bbfdm_get_references(ctx, "Device.IP.Interface.*.IPv4Address.", "IPAddress", ipaddr, value); + // save it for later + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "ipv4path", *value); + } + + return 0; +} + +static int set_IPv6rdInterfaceSetting_AddressSource(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *allowed_objects[] = {"Device.IP.Interface.*.IPv4Address.", NULL}; + struct dm_reference reference = {0}; + + bbfdm_get_reference_linker(ctx, value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, reference.path, -1, 256, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + break; + case VALUESET: + if (DM_STRLEN(reference.value)) { + check_and_add_6rd_section(&data); + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ipaddr", reference.value); + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "ipv4path", reference.path); + } + break; + } + return 0; +} + +static int get_IPv6rdInterfaceSetting_TunnelInterface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + // Tunnel, Tunneled interfaces are not yet supported + // when their support is added, we can update this function + *value = ""; + return 0; +} + +static int get_IPv6rdInterfaceSetting_TunneledInterface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + // Tunnel, Tunneled interfaces are not yet supported + // when their support is added, we can update this function + *value = ""; + return 0; +} + +/********************************************************************************************************************************** +* OBJ & PARAM DEFINITION +***********************************************************************************************************************************/ +/* *** Device. *** */ +DMOBJ tDeviceIPv6rdObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/ +{"IPv6rd", &DMREAD, NULL, NULL, "file:/lib/netifd/proto/6rd.sh,/etc/config/network", NULL, NULL, NULL, tIPv6rdObj, tIPv6rdParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +/* *** Device.IPv6rd. *** */ +DMOBJ tIPv6rdObj[] = { +/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys */ +{"InterfaceSetting", &DMREAD, NULL, NULL, NULL, browseIPv6rdInterfaceSettingInst, NULL, NULL, NULL, tIPv6rdInterfaceSettingParams, NULL, BBFDM_BOTH, NULL}, +{0} +}; + +DMLEAF tIPv6rdParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */ +{"Enable", &DMWRITE, DMT_BOOL, get_IPv6rd_Enable, set_IPv6rd_Enable, BBFDM_BOTH}, +{"InterfaceSettingNumberOfEntries", &DMREAD, DMT_UNINT, get_IPv6rd_InterfaceSettingNumberOfEntries, NULL, BBFDM_BOTH}, +{0} +}; + +/* *** Device.IPv6rd.InterfaceSetting.{i}. *** */ +DMLEAF tIPv6rdInterfaceSettingParams[] = { +/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */ +{"Enable", &DMWRITE, DMT_BOOL, get_IPv6rdInterfaceSetting_Enable, set_IPv6rdInterfaceSetting_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_IPv6rdInterfaceSetting_Status, NULL, BBFDM_BOTH}, +{"Alias", &DMWRITE, DMT_STRING, get_IPv6rdInterfaceSetting_Alias, set_IPv6rdInterfaceSetting_Alias, BBFDM_BOTH}, +{"BorderRelayIPv4Addresses", &DMWRITE, DMT_STRING, get_IPv6rdInterfaceSetting_BorderRelayIPv4Addresses, set_IPv6rdInterfaceSetting_BorderRelayIPv4Addresses, BBFDM_BOTH}, +{"AllTrafficToBorderRelay", &DMWRITE, DMT_BOOL, get_IPv6rdInterfaceSetting_AllTrafficToBorderRelay, set_IPv6rdInterfaceSetting_AllTrafficToBorderRelay, BBFDM_BOTH}, +{"SPIPv6Prefix", &DMWRITE, DMT_STRING, get_IPv6rdInterfaceSetting_SPIPv6Prefix, set_IPv6rdInterfaceSetting_SPIPv6Prefix, BBFDM_BOTH}, +{"IPv4MaskLength", &DMWRITE, DMT_UNINT, get_IPv6rdInterfaceSetting_IPv4MaskLength, set_IPv6rdInterfaceSetting_IPv4MaskLength, BBFDM_BOTH}, +{"AddressSource", &DMWRITE, DMT_STRING, get_IPv6rdInterfaceSetting_AddressSource, set_IPv6rdInterfaceSetting_AddressSource, BBFDM_BOTH, DM_FLAG_REFERENCE}, +{"TunnelInterface", &DMREAD, DMT_STRING, get_IPv6rdInterfaceSetting_TunnelInterface, NULL, BBFDM_BOTH}, +{"TunneledInterface", &DMREAD, DMT_STRING, get_IPv6rdInterfaceSetting_TunneledInterface, NULL, BBFDM_BOTH}, +{0} +}; + diff --git a/src/ipv6rd.h b/src/ipv6rd.h new file mode 100644 index 0000000000000000000000000000000000000000..65102af739502316d894474f7bca5958d5bfb43e --- /dev/null +++ b/src/ipv6rd.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2023 iopsys Software Solutions AB + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * Author: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu> + */ + +#ifndef __IPV6RD_H +#define __IPV6RD_H + +#include <libbbfdm-api/dmcommon.h> + +extern DMOBJ tDeviceIPv6rdObj[]; +extern DMOBJ tIPv6rdObj[]; +extern DMLEAF tIPv6rdParams[]; +extern DMLEAF tIPv6rdInterfaceSettingParams[]; + + +#endif //__IPV6RD_H + diff --git a/src/net_plugin.c b/src/net_plugin.c index fc1aa616d6b775e8200eae01fc26842e5fbf7d57..b8bab34a4506d7359b53eefd6f19bea3f8d64549 100644 --- a/src/net_plugin.c +++ b/src/net_plugin.c @@ -13,6 +13,7 @@ #include "ppp.h" #include "routing.h" #include "routeradvertisement.h" +#include "ipv6rd.h" DM_MAP_OBJ tDynamicObj[] = { /* parentobj, nextobject, parameter */ @@ -21,5 +22,6 @@ DM_MAP_OBJ tDynamicObj[] = { {"Device.", tDevicePPPObj, NULL}, {"Device.", tDeviceRoutingObj, NULL}, {"Device.", tDeviceRouterAdvertisementObj, NULL}, +{"Device.", tDeviceIPv6rdObj, NULL}, {0} };