diff --git a/bin/Makefile.am b/bin/Makefile.am index 92457c8..ecd113d 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -264,3 +264,26 @@ icwmp_udpechoserverd_LDFLAGS = \ icwmp_udpechoserverd_LDADD = \ $(AM_LIBS) \ $(LIBUCI_LIBS) + +bin_PROGRAMS += icwmp_twampd + +icwmp_twampd_SOURCES = \ + ../twamp/twamp.c \ + ../twamp/twamp.h \ + ../twamp/twamptimestamp.c \ + ../twamp/twampuci.c \ + ../twamp/twampuci.h \ + ../twamp/twamplog.c \ + ../twamp/twamplog.h + +icwmp_twampd_CFLAGS = \ + $(AM_CFLAGS) \ + $(LIBUCI_CFLAGS) + +icwmp_twampd_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(LIBUCI_LDFLAGS) + +icwmp_twampd_LDADD = \ + $(AM_LIBS) \ + $(LIBUCI_LIBS) diff --git a/config/cwmp_twamp b/config/cwmp_twamp new file mode 100644 index 0000000..ad275b9 --- /dev/null +++ b/config/cwmp_twamp @@ -0,0 +1,4 @@ +config cwmp 'twamp' + option id '1' + #Log levels: Critical=0, Warning=1, Notice=2, Info=3, Debug=4 + option log_level '3' diff --git a/dm/dmtree/common/root.c b/dm/dmtree/common/root.c index 9b484f1..796ced1 100644 --- a/dm/dmtree/common/root.c +++ b/dm/dmtree/common/root.c @@ -61,6 +61,7 @@ #include "users.h" #include "dsl.h" #include "dhcpv6.h" + /* *** CWMP *** */ DMOBJ tEntry098Obj[] = { /* OBJ, permission, addobj, delobj, browseinstobj, finform, NOTIFICATION, nextobj, leaf, linker*/ @@ -128,7 +129,7 @@ DMOBJ tRoot_181_Obj[] = { {CUSTOM_PREFIX"WiFiLife", &DMREAD, NULL, NULL, NULL, NULL, NULL, &DMNONE, X_IOPSYS_EU_WiFiLifeObj, X_IOPSYS_EU_WiFiLifeParams, NULL}, {"Bridging",&DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tBridgingObj, NULL, NULL}, {"WiFi",&DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tWifiObj, tWifiParams, NULL}, -{"IP",&DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tIPObj, NULL, NULL}, +{"IP",&DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tIPObj, tIPParams, NULL}, {"Ethernet", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tEthernetObj, NULL, NULL}, {"DSL",&DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tDSLObj, tDSLParams, NULL}, {"ATM",&DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tAtmObj, NULL, NULL}, diff --git a/dm/dmtree/tr181/ip.c b/dm/dmtree/tr181/ip.c index 828365b..807080f 100644 --- a/dm/dmtree/tr181/ip.c +++ b/dm/dmtree/tr181/ip.c @@ -32,12 +32,16 @@ DMOBJ tIPObj[] = { {0} }; -DMLEAF tIPintParams[] = { +DMLEAF tIPParams[] = { /* PARAM, permission, type, getvlue, setvalue, forced_inform, notification*/ -{"Enable", &DMWRITE, DMT_BOOL, get_ip_interface_enable, set_ip_interface_enable, NULL, NULL}, -{"Status", &DMREAD, DMT_STRING, get_ip_interface_status, NULL, NULL, NULL}, -{"Name", &DMREAD, DMT_STRING, get_ip_interface_name, NULL, NULL, NULL}, -{"LowerLayers", &DMWRITE, DMT_STRING, get_ip_int_lower_layer, set_ip_int_lower_layer, NULL, NULL}, +{"IPv4Capable", &DMREAD, DMT_BOOL, get_IP_IPv4Capable, NULL, NULL, NULL}, +{"IPv4Enable", &DMWRITE, DMT_BOOL, get_IP_IPv4Enable, set_IP_IPv4Enable, NULL, NULL}, +{"IPv4Status", &DMREAD, DMT_STRING, get_IP_IPv4Status, NULL, NULL, NULL}, +{"IPv6Capable", &DMREAD, DMT_BOOL, get_IP_IPv6Capable, NULL, NULL, NULL}, +{"IPv6Enable", &DMWRITE, DMT_BOOL, get_IP_IPv6Enable, set_IP_IPv6Enable, NULL, NULL}, +{"IPv6Status", &DMREAD, DMT_STRING, get_IP_IPv6Status, NULL, NULL, NULL}, +{"ULAPrefix", &DMWRITE, DMT_STRING, get_IP_ULAPrefix, set_IP_ULAPrefix, NULL, NULL}, +{"InterfaceNumberOfEntries", &DMREAD, DMT_UNINT, get_IP_InterfaceNumberOfEntries, NULL, NULL, NULL}, {0} }; @@ -46,15 +50,40 @@ DMOBJ tInterfaceObj[] = { /* OBJ, permission, addobj, delobj, checkobj, browseinstobj, forced_inform, notification, nextobj, leaf, linker*/ {"IPv4Address", &DMWRITE, add_ipv4, delete_ipv4, NULL, browseIfaceIPv4Inst, NULL, NULL, NULL, tIPv4Params, NULL}, {"IPv6Address", &DMWRITE, add_ipv6, delete_ipv6, NULL, browseIfaceIPv6Inst, NULL, NULL, NULL, tIPv6Params, NULL}, +{"IPv6Prefix", &DMWRITE, add_ipv6_prefix, delete_ipv6_prefix, NULL, browseIfaceIPv6PrefixInst, NULL, NULL, NULL, tIPv6PrefixParams, get_linker_ipv6_prefix}, {"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tIPInterfaceStatsParams, NULL}, +{"TWAMPReflector", &DMWRITE, addObjIPInterfaceTWAMPReflector, delObjIPInterfaceTWAMPReflector, NULL, browseIPInterfaceTWAMPReflectorInst, NULL, NULL, NULL, tIPInterfaceTWAMPReflectorParams, NULL}, +{0} +}; + +DMLEAF tIPintParams[] = { +/* PARAM, permission, type, getvlue, setvalue, forced_inform, notification*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterface_Enable, set_IPInterface_Enable, NULL, NULL}, +{"IPv4Enable", &DMWRITE, DMT_BOOL, get_IPInterface_IPv4Enable, set_IPInterface_IPv4Enable, NULL, NULL}, +{"IPv6Enable", &DMWRITE, DMT_BOOL, get_IPInterface_IPv6Enable, set_IPInterface_IPv6Enable, NULL, NULL}, +{"Status", &DMREAD, DMT_STRING, get_IPInterface_Status, NULL, NULL, NULL}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterface_Alias, set_IPInterface_Alias, NULL, NULL}, +{"Name", &DMREAD, DMT_STRING, get_IPInterface_Name, NULL, NULL, NULL}, +{"LastChange", &DMREAD, DMT_UNINT, get_IPInterface_LastChange, NULL, NULL, NULL}, +{"LowerLayers", &DMWRITE, DMT_STRING, get_IPInterface_LowerLayers, set_IPInterface_LowerLayers, NULL, NULL}, +{"Router", &DMWRITE, DMT_STRING, get_IPInterface_Router, set_IPInterface_Router, NULL, NULL}, +{"Reset", &DMWRITE, DMT_BOOL, get_IPInterface_Reset, set_IPInterface_Reset, NULL, NULL}, +{"MaxMTUSize", &DMWRITE, DMT_UNINT, get_IPInterface_MaxMTUSize, set_IPInterface_MaxMTUSize, NULL, NULL}, +{"Type", &DMREAD, DMT_STRING, get_IPInterface_Type, NULL, NULL, NULL}, +{"Loopback", &DMWRITE, DMT_BOOL, get_IPInterface_Loopback, set_IPInterface_Loopback, NULL, NULL}, +{"IPv4AddressNumberOfEntries", &DMREAD, DMT_UNINT, get_IPInterface_IPv4AddressNumberOfEntries, NULL, NULL, NULL}, +{"IPv6AddressNumberOfEntries", &DMREAD, DMT_UNINT, get_IPInterface_IPv6AddressNumberOfEntries, NULL, NULL, NULL}, +{"IPv6PrefixNumberOfEntries", &DMREAD, DMT_UNINT, get_IPInterface_IPv6PrefixNumberOfEntries, NULL, NULL, NULL}, +{"TWAMPReflectorNumberOfEntries", &DMREAD, DMT_UNINT, get_IPInterface_TWAMPReflectorNumberOfEntries, NULL, NULL, NULL}, {0} }; /* *** Device.IP.Interface.{i}.IPv4Address.{i}. *** */ DMLEAF tIPv4Params[] = { /* PARAM, permission, type, getvlue, setvalue, forced_inform, notification*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterface_Enable, set_IPInterface_Enable, &IPv4INFRM, NULL}, +{"Status", &DMREAD, DMT_STRING, get_IPInterface_Status, NULL, &IPv4INFRM, NULL}, {"Alias", &DMWRITE, DMT_STRING, get_ipv4_alias, set_ipv4_alias, &IPv4INFRM, NULL}, -{"Enable", &DMWRITE, DMT_BOOL, get_ip_interface_enable, set_ip_interface_enable, &IPv4INFRM, NULL}, {CUSTOM_PREFIX"FirewallEnabled", &DMWRITE, DMT_BOOL, get_firewall_enabled, set_firewall_enabled, &IPv4INFRM, NULL}, {"IPAddress", &DMWRITE, DMT_STRING, get_ipv4_address, set_ipv4_address, &IPv4INFRM, NULL}, {"SubnetMask", &DMWRITE, DMT_STRING, get_ipv4_netmask, set_ipv4_netmask, &IPv4INFRM, NULL}, @@ -65,10 +94,32 @@ DMLEAF tIPv4Params[] = { /* *** Device.IP.Interface.{i}.IPv6Address.{i}. *** */ DMLEAF tIPv6Params[] = { /* PARAM, permission, type, getvlue, setvalue, forced_inform, notification*/ -{"Alias", &DMWRITE, DMT_STRING, get_ipv6_alias, set_ipv6_alias, &IPv6INFRM, NULL}, -{"Enable", &DMREAD, DMT_BOOL, get_ip_enable, NULL, &IPv6INFRM, NULL}, -{"IPAddress", &DMWRITE, DMT_STRING, get_ipv6_address, set_ipv6_address, &IPv6INFRM, NULL}, -{"Origin", &DMWRITE, DMT_STRING, get_ipv6_addressing_type, set_ipv6_addressing_type, &IPv6INFRM, NULL}, +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv6Address_Enable, set_IPInterfaceIPv6Address_Enable, &IPv6INFRM, NULL}, +{"Status", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Address_Status, NULL, &IPv6INFRM, NULL}, +{"IPAddressStatus", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Address_IPAddressStatus, NULL, &IPv6INFRM, NULL}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Address_Alias, set_IPInterfaceIPv6Address_Alias, &IPv6INFRM, NULL}, +{"IPAddress", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Address_IPAddress, set_IPInterfaceIPv6Address_IPAddress, &IPv6INFRM, NULL}, +{"Origin", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Address_Origin, NULL, &IPv6INFRM, NULL}, +{"Prefix", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Address_Prefix, set_IPInterfaceIPv6Address_Prefix, &IPv6INFRM, NULL}, +{"PreferredLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Address_PreferredLifetime, set_IPInterfaceIPv6Address_PreferredLifetime, &IPv6INFRM, NULL}, +{"ValidLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Address_ValidLifetime, set_IPInterfaceIPv6Address_ValidLifetime, &IPv6INFRM, NULL}, +{0} +}; + +/* *** Device.IP.Interface.{i}.IPv6Prefix.{i}. *** */ +DMLEAF tIPv6PrefixParams[] = { +/* PARAM, permission, type, getvlue, setvalue, forced_inform, notification*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceIPv6Prefix_Enable, set_IPInterfaceIPv6Prefix_Enable, NULL, NULL}, +{"Status", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Prefix_Status, NULL, NULL, NULL}, +{"PrefixStatus", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Prefix_PrefixStatus, NULL, NULL, NULL}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_Alias, set_IPInterfaceIPv6Prefix_Alias, NULL, NULL}, +{"Prefix", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_Prefix, set_IPInterfaceIPv6Prefix_Prefix, NULL, NULL}, +{"Origin", &DMREAD, DMT_STRING, get_IPInterfaceIPv6Prefix_Origin, NULL, NULL, NULL}, +{"StaticType", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_StaticType, set_IPInterfaceIPv6Prefix_StaticType, NULL, NULL}, +{"ParentPrefix", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_ParentPrefix, set_IPInterfaceIPv6Prefix_ParentPrefix, NULL, NULL}, +{"ChildPrefixBits", &DMWRITE, DMT_STRING, get_IPInterfaceIPv6Prefix_ChildPrefixBits, set_IPInterfaceIPv6Prefix_ChildPrefixBits, NULL, NULL}, +{"PreferredLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Prefix_PreferredLifetime, set_IPInterfaceIPv6Prefix_PreferredLifetime, NULL, NULL}, +{"ValidLifetime", &DMWRITE, DMT_TIME, get_IPInterfaceIPv6Prefix_ValidLifetime, set_IPInterfaceIPv6Prefix_ValidLifetime, NULL, NULL}, {0} }; @@ -83,6 +134,20 @@ DMLEAF tIPInterfaceStatsParams[] = { {"ErrorsReceived", &DMREAD, DMT_UNINT, get_ip_interface_statistics_rx_errors, NULL, NULL, NULL}, {"DiscardPacketsSent", &DMREAD, DMT_UNINT, get_ip_interface_statistics_tx_discardpackets, NULL, NULL, NULL}, {"DiscardPacketsReceived", &DMREAD, DMT_UNINT, get_ip_interface_statistics_rx_discardpackets, NULL, NULL, NULL}, +{"MulticastPacketsReceived", &DMREAD, DMT_UNINT, get_ip_interface_statistics_rx_multicastpackets, NULL, NULL, NULL}, +{0} +}; + +/* *** Device.IP.Interface.{i}.TWAMPReflector.{i}. *** */ +DMLEAF tIPInterfaceTWAMPReflectorParams[] = { +/* PARAM, permission, type, getvlue, setvalue, forced_inform, notification*/ +{"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceTWAMPReflector_Enable, set_IPInterfaceTWAMPReflector_Enable, NULL, NULL}, +{"Status", &DMREAD, DMT_STRING, get_IPInterfaceTWAMPReflector_Status, NULL, NULL, NULL}, +{"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceTWAMPReflector_Alias, set_IPInterfaceTWAMPReflector_Alias, NULL, NULL}, +{"Port", &DMWRITE, DMT_UNINT, get_IPInterfaceTWAMPReflector_Port, set_IPInterfaceTWAMPReflector_Port, NULL, NULL}, +{"MaximumTTL", &DMWRITE, DMT_UNINT, get_IPInterfaceTWAMPReflector_MaximumTTL, set_IPInterfaceTWAMPReflector_MaximumTTL, NULL, NULL}, +{"IPAllowedList", &DMWRITE, DMT_STRING, get_IPInterfaceTWAMPReflector_IPAllowedList, set_IPInterfaceTWAMPReflector_IPAllowedList, NULL, NULL}, +{"PortAllowedList", &DMWRITE, DMT_STRING, get_IPInterfaceTWAMPReflector_PortAllowedList, set_IPInterfaceTWAMPReflector_PortAllowedList, NULL, NULL}, {0} }; @@ -339,14 +404,91 @@ unsigned char get_ipv6_finform(char *refparam, struct dmctx *dmctx, void *data, /************************************************************* * INIT /*************************************************************/ -inline int init_ip_args(struct ip_args *args, struct uci_section *s, char *ip_4address, char *ip_6address) +inline int init_ip_args(struct ip_args *args, struct uci_section *s, char *ip_4address) { args->ip_sec = s; args->ip_4address = ip_4address; - args->ip_6address = ip_6address; return 0; } +inline int init_ipv6_args(struct ipv6_args *args, struct uci_section *s, char *ip_6address, char *ip_6mask, char *ip_6preferred, char *ip_6valid) +{ + args->ip_sec = s; + args->ip_6address = ip_6address; + args->ip_6mask = ip_6mask; + args->ip_6preferred = ip_6preferred; + args->ip_6valid = ip_6valid; + return 0; +} + +inline int init_ipv6prefix_args(struct ipv6prefix_args *args, struct uci_section *s, char *ip_6prefixaddress, char *ip_6prefixmask, char *ip_6prefixpreferred, char *ip_6prefixvalid) +{ + args->ip_sec = s; + args->ip_6prefixaddress = ip_6prefixaddress; + args->ip_6prefixmask = ip_6prefixmask; + args->ip_6prefixpreferred = ip_6prefixpreferred; + args->ip_6prefixvalid = ip_6prefixvalid; + return 0; +} + +/************************************************************* + * COMMON Functions +/*************************************************************/ +static char *ubus_call_get_value_with_two_objects(char *interface, char *obj1, char *obj2, char *key) +{ + json_object *res, *jobj1, *jobj2; + char *value = ""; + + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); + if (res) + { + jobj1 = dmjson_select_obj_in_array_idx(res, 0, 1, obj1); + if(jobj1) + jobj2 = dmjson_get_obj(jobj1, 1, obj2); + if(jobj2) + value = dmjson_get_value(jobj2, 1, key); + } + return value; +} + +static char *ubus_call_get_value(char *interface, char *obj, char *key) +{ + json_object *res, *jobj; + char *value = ""; + + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); + if (res) + { + jobj = dmjson_select_obj_in_array_idx(res, 0, 1, obj); + value = dmjson_get_value(jobj, 1, key); + } + return value; +} + +static char *get_child_prefix_linker(char *interface) +{ + char *address = NULL, *mask = NULL, *value; + json_object *res, *jobj, *jobj1, *jobj2; + + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); + if(res) { + jobj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv6-prefix"); + if(jobj) { + jobj1 = dmjson_get_obj(jobj, 1, "assigned"); + if(jobj1) { + jobj2 = dmjson_get_obj(jobj1, 1, "lan"); + if(jobj2) { + address = dmjson_get_value(jobj2, 1, "address"); + mask = dmjson_get_value(jobj2, 1, "mask"); + dmasprintf(&value, "%s/%s", address,mask); + return value; + } + } + } + } + return ""; +} + /************************************************************* * GET & SET PARAM /*************************************************************/ @@ -356,12 +498,6 @@ int get_diag_enable_true(char *refparam, struct dmctx *ctx, void *data, char *in return 0; } -int get_diag_enable_false(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value = "0"; - return 0; -} - /* * *** Device.IP.Diagnostics.IPPing. *** */ @@ -2525,29 +2661,125 @@ int get_IPDiagnosticsServerSelectionDiagnostics_MaximumResponseTime(char *refpar /* * *** Device.IP. *** */ - -int get_ip_interface_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +int get_IP_IPv4Capable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *lan_name = section_name(((struct ip_args *)data)->ip_sec); - get_interface_enable_ubus(lan_name, refparam, ctx, value); + *value = "1"; return 0; } -int set_ip_interface_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +int get_IP_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *lan_name; - switch (action) { + *value = "1"; + return 0; +} + +int set_IP_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { case VALUECHECK: break; case VALUESET: - lan_name = section_name(((struct ip_args *)data)->ip_sec); - set_interface_enable_ubus(lan_name, refparam, ctx, action, value); break; } return 0; } -int get_ip_interface_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +int get_IP_IPv4Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Enabled"; + return 0; +} + +int get_IP_IPv6Capable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "1"; + return 0; +} + +int get_IP_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "1"; + return 0; +} + +int set_IP_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IP_IPv6Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Enabled"; + return 0; +} + +int get_IP_ULAPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_option_value_string("network", "globals", "ula_prefix", value); + return 0; +} + +int set_IP_ULAPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + dmuci_set_value("network", "globals", "ula_prefix", value); + break; + } + return 0; +} + +int get_IP_InterfaceNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s = NULL; + char *inst = NULL; + int cnt = 0; + + uci_path_foreach_sections(icwmpd, "dmmap_network", "interface", s) { + dmuci_get_value_by_section_string(s, "ip_int_instance", &inst); + if(inst[0] != '\0') + cnt++; + } + dmasprintf(value, "%d", cnt); + return 0; +} + +/* + * *** Device.IP.Interface. *** + */ +int get_IPInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *v; + dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "disabled", &v); + *value = (*v != '1') ? "1" : "0"; + return 0; +} + +int set_IPInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + unsigned char b; + switch (action) { + case VALUECHECK: + if (string_to_bool(value, &b)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "disabled", (b) ? "0" : "1"); + break; + } + return 0; +} + +int get_IPInterface_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { json_object *res; char *lan_name = section_name(((struct ip_args *)data)->ip_sec), *val= NULL; @@ -2557,12 +2789,219 @@ int get_ip_interface_status(char *refparam, struct dmctx *ctx, void *data, char return 0; } -int get_ip_interface_name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +int get_IPInterface_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = dmstrdup(section_name(((struct ip_args *)data)->ip_sec)); return 0; } +int get_IPInterface_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "1"; + return 0; +} + +int set_IPInterface_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterface_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *v; + dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "ipv6", &v); + *value = (*v != '0') ? "1" : "0"; + return 0; +} + +int set_IPInterface_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + unsigned char b; + switch (action) { + case VALUECHECK: + if (string_to_bool(value, &b)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "ipv6", (b) ? "" : "0"); + break; + } + return 0; +} + +int get_IPInterface_LastChange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *res; + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", section_name(((struct ip_args *)data)->ip_sec), String}}, 1, &res); + DM_ASSERT(res, *value = ""); + *value = dmjson_get_value(res, 1, "uptime"); + return 0; +} + +int get_IPInterface_Router(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Device.Routing.Router.1."; + return 0; +} + +int set_IPInterface_Router(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "0"; + return 0; +} + +int set_IPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + unsigned char b; + switch (action) { + case VALUECHECK: + if (string_to_bool(value, &b)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + if(b) { + set_interface_enable_ubus(section_name(((struct ip_args *)data)->ip_sec), refparam, ctx, action, "0"); + set_interface_enable_ubus(section_name(((struct ip_args *)data)->ip_sec), refparam, ctx, action, "1"); + } + break; + } + return 0; +} + +int get_IPInterface_MaxMTUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *res, *diag; + char *device= NULL; + + dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "mtu", value); + if(*value[0] == '\0') { + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", section_name(((struct ip_args *)data)->ip_sec), String}}, 1, &res); + DM_ASSERT(res, *value = ""); + device = dmjson_get_value(res, 1, "device"); + if(device) { + dmubus_call("network.device", "status", UBUS_ARGS{{"name", device, String}}, 1, &diag); + DM_ASSERT(diag, *value = ""); + *value = dmjson_get_value(diag, 1, "mtu"); + } + return 0; + } + return 0; +} + +int set_IPInterface_MaxMTUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "mtu", value); + break; + } + return 0; +} + +int get_IPInterface_Type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (strcmp(section_name(((struct ip_args *)data)->ip_sec), "loopback") == 0) + *value = "Loopback"; + else + *value = "Normal"; + return 0; +} + +int get_IPInterface_Loopback(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if (strcmp(section_name(((struct ip_args *)data)->ip_sec), "loopback") == 0) + *value = "1"; + else + *value = "0"; + return 0; +} + +int set_IPInterface_Loopback(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterface_IPv4AddressNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s; + char *inst; + + *value = "0"; + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "interface", "section_name", section_name(((struct ip_args *)data)->ip_sec), s) { + dmuci_get_value_by_section_string(s, "ipv4_instance", &inst); + if(inst[0] != '\0') + *value = "1"; + } + return 0; +} + +int get_IPInterface_IPv6AddressNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s; + int cnt = 0; + + *value = "0"; + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6", "section_name", section_name(((struct ip_args *)data)->ip_sec), s) { + cnt++; + } + dmasprintf(value, "%d", cnt); + return 0; +} + +int get_IPInterface_IPv6PrefixNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s; + int cnt = 0; + + *value = "0"; + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6prefix", "section_name", section_name(((struct ip_args *)data)->ip_sec), s) { + cnt++; + } + dmasprintf(value, "%d", cnt); + return 0; +} + +int get_IPInterface_TWAMPReflectorNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *s = NULL; + int cnt = 0; + uci_foreach_option_eq("cwmp_twamp", "twamp_refector", "interface", section_name(((struct ip_args *)data)->ip_sec), s) { + cnt++; + } + dmasprintf(value, "%d", cnt); + return 0; +} + +/* + * *** Device.IP.Interface.{i}.IPv4Address.{i}. *** + */ int get_firewall_enabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { get_interface_firewall_enabled(section_name(((struct ip_args *)data)->ip_sec), refparam, ctx, value); @@ -2599,7 +3038,21 @@ int set_ipv4_address(char *refparam, struct dmctx *ctx, void *data, char *instan int get_ipv4_netmask(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "netmask", value); + json_object *res, *jobj; + char *mask; + + dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "netmask", &mask); + if (mask[0] == '\0') { + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", section_name(((struct ip_args *)data)->ip_sec), String}}, 1, &res); + if (res) { + jobj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv4-address"); + mask = dmjson_get_value(jobj, 1, "mask"); + if (mask[0] == '\0') + return 0; + mask = cidr2netmask(atoi(mask)); + } + } + *value = mask; return 0; } @@ -2650,39 +3103,7 @@ int set_ipv4_addressing_type(char *refparam, struct dmctx *ctx, void *data, char return 0; } -int get_ipv6_addressing_type (char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "proto", value); - if (strcmp(*value, "static") == 0) - *value = "Static"; - else if (strcmp(*value, "dhcpv6") == 0) - *value = "DHCPv6"; - else - *value = ""; - return 0; -} - -int set_ipv6_addressing_type(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) -{ - char *proto; - switch (action) { - case VALUECHECK: - return 0; - case VALUESET: - if(strcasecmp(value, "static") == 0) { - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "proto", "static"); - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "ip6addr", "0.0.0.0"); - } - if(strcasecmp(value, "dhcpv6") == 0) { - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "proto", "dhcpv6"); - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "ip6addr", ""); - } - return 0; - } - return 0; -} - -int get_ip_int_lower_layer(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +int get_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { struct uci_section *dmmap_section; char *wifname, *wtype, *br_inst, *mg, *device, *proto; @@ -2750,7 +3171,7 @@ int get_ip_int_lower_layer(char *refparam, struct dmctx *ctx, void *data, char * return 0; } -int set_ip_int_lower_layer(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +int set_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { char *linker= NULL, *pch, *spch, *dup, *b_key, *proto, *ipaddr, *ip_inst, *ipv4_inst, *p, *type; char *newvalue= NULL; @@ -2800,20 +3221,25 @@ int set_ip_int_lower_layer(char *refparam, struct dmctx *ctx, void *data, char * return 0; } -int get_ipv6_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +/* + * *** Device.IP.Interface.{i}.IPv6Address.{i}. *** + */ +int get_IPInterfaceIPv6Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = ((struct ip_args *)data)->ip_6address; + *value = ((struct ipv6_args *)data)->ip_6address; + if(((struct ipv6_args *)data)->ip_6mask[0] != '\0') + dmasprintf(value, "%s/%s", ((struct ipv6_args *)data)->ip_6address, ((struct ipv6_args *)data)->ip_6mask); return 0; } -int set_ipv6_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +int set_IPInterfaceIPv6Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { char *proto; switch (action) { case VALUECHECK: return 0; case VALUESET: - dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "proto", &proto); + dmuci_get_value_by_section_string(((struct ipv6_args *)data)->ip_sec, "proto", &proto); if(strcmp(proto, "static") == 0) dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "ip6addr", value); return 0; @@ -2821,12 +3247,320 @@ int set_ipv6_address(char *refparam, struct dmctx *ctx, void *data, char *instan return 0; } -int get_ip_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +int get_IPInterfaceIPv6Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = "true"; + *value = "1"; return 0; } +int set_IPInterfaceIPv6Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterfaceIPv6Address_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Enabled"; + return 0; +} + +int get_IPInterfaceIPv6Address_IPAddressStatus(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if(((struct ipv6_args *)data)->ip_6valid[0] != '\0') + *value = "Preferred"; + else + *value = "Unknown"; + return 0; +} + +int get_IPInterfaceIPv6Address_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ubus_call_get_value_with_two_objects(section_name(((struct ipv6_args *)data)->ip_sec), "ipv6-prefix-assignment", "local-address", "address"); + if(*value[0] != '\0') + *value = "AutoConfigured"; + else { + dmuci_get_value_by_section_string(((struct ipv6_args *)data)->ip_sec, "proto", value); + if (strcmp(*value, "static") == 0) + *value = "Static"; + else if (strcmp(*value, "dhcpv6") == 0) + *value = "DHCPv6"; + else + *value = "WellKnown"; + } + return 0; +} + +int get_IPInterfaceIPv6Address_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *dmmap_section; + char *inst; + + get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(((struct ipv6_args *)data)->ip_sec), &dmmap_section); + dmuci_get_value_by_section_string(dmmap_section, "ip_int_instance", &inst); + + *value = ""; + if(((struct ipv6prefix_args *)data)->ip_6prefixaddress[0] != '\0') + dmasprintf(value, "Device.IP.Interface.%s.IPv6Prefix.1.", inst); + return 0; +} + +int set_IPInterfaceIPv6Address_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterfaceIPv6Address_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char local_time[32] = {0}; + char *preferred = ((struct ipv6_args *)data)->ip_6preferred; + *value = "0001-01-01T00:00:00Z"; + if (get_shift_time_time(atoi(preferred), local_time, sizeof(local_time)) == -1) + return 0; + *value = dmstrdup(local_time); + return 0; +} + +int set_IPInterfaceIPv6Address_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char buf[32] = "", *proto; + + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + dmuci_get_value_by_section_string(((struct ipv6_args *)data)->ip_sec, "proto", &proto); + if(strcasecmp(proto, "static") == 0) { + get_shift_time_shift(value, buf); + if (!(*buf)) + return 0; + dmuci_set_value_by_section(((struct ipv6_args *)data)->ip_sec, "adv_preferred_lifetime", buf); + } + return 0; + } + return 0; +} + +int get_IPInterfaceIPv6Address_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char local_time[32] = {0}; + char *preferred = ((struct ipv6_args *)data)->ip_6valid; + *value = "0001-01-01T00:00:00Z"; + if (get_shift_time_time(atoi(preferred), local_time, sizeof(local_time)) == -1) + return 0; + *value = dmstrdup(local_time); + return 0; +} + +int set_IPInterfaceIPv6Address_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char buf[32] = "", *proto; + + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + dmuci_get_value_by_section_string(((struct ipv6_args *)data)->ip_sec, "proto", &proto); + if(strcasecmp(proto, "static") == 0) { + get_shift_time_shift(value, buf); + if (!(*buf)) + return 0; + dmuci_set_value_by_section(((struct ipv6_args *)data)->ip_sec, "adv_valid_lifetime", buf); + } + return 0; + } + return 0; +} + +/* + * *** Device.IP.Interface.{i}.IPv6Prefix.{i}. *** + */ +int get_IPInterfaceIPv6Prefix_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "1"; + return 0; +} + +int set_IPInterfaceIPv6Prefix_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterfaceIPv6Prefix_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Enabled"; + return 0; +} + +int get_IPInterfaceIPv6Prefix_PrefixStatus(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + if(((struct ipv6prefix_args *)data)->ip_6prefixvalid[0] != '\0') + *value = "Preferred"; + else + *value = "Unknown"; + return 0; +} + +int get_IPInterfaceIPv6Prefix_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ((struct ipv6prefix_args *)data)->ip_6prefixaddress; + if(((struct ipv6prefix_args *)data)->ip_6prefixmask[0] != '\0') + dmasprintf(value, "%s/%s", ((struct ipv6prefix_args *)data)->ip_6prefixaddress, ((struct ipv6prefix_args *)data)->ip_6prefixmask); + return 0; +} + +int set_IPInterfaceIPv6Prefix_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *proto; + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + dmuci_get_value_by_section_string(((struct ipv6prefix_args *)data)->ip_sec, "proto", &proto); + if(strcmp(proto, "static") == 0) + dmuci_set_value_by_section(((struct ipv6prefix_args *)data)->ip_sec, "ip_6prefixaddress", value); + return 0; + } + return 0; +} + +int get_IPInterfaceIPv6Prefix_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = ubus_call_get_value(section_name(((struct ipv6prefix_args *)data)->ip_sec), "ipv6-prefix-assignment", "address"); + if(*value[0] != '\0') + *value = "AutoConfigured"; + else { + dmuci_get_value_by_section_string(((struct ipv6prefix_args *)data)->ip_sec, "proto", value); + if (strcmp(*value, "static") == 0) + *value = "Static"; + else if (strcmp(*value, "dhcpv6") == 0) + *value = "DHCPv6"; + else + *value = "WellKnown"; + } + return 0; +} + +int get_IPInterfaceIPv6Prefix_StaticType(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = "Static"; + return 0; +} + +int set_IPInterfaceIPv6Prefix_StaticType(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterfaceIPv6Prefix_ParentPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *linker; + dmasprintf(&linker, "%s/%s", ((struct ipv6prefix_args *)data)->ip_6prefixaddress, ((struct ipv6prefix_args *)data)->ip_6prefixmask); + if(linker[0] != '\0') + adm_entry_get_linker_param(ctx, dm_print_path("%s%cIP%Interface%c", dmroot, dm_delim, dm_delim, dm_delim), linker, value); + if (*value == NULL) + *value = ""; + return 0; +} + +int set_IPInterfaceIPv6Prefix_ParentPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterfaceIPv6Prefix_ChildPrefixBits(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + *value = get_child_prefix_linker(section_name(((struct ipv6prefix_args *)data)->ip_sec)); + return 0; +} + +int set_IPInterfaceIPv6Prefix_ChildPrefixBits(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterfaceIPv6Prefix_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char local_time[32] = {0}; + char *preferred = ((struct ipv6prefix_args *)data)->ip_6prefixpreferred; + *value = "0001-01-01T00:00:00Z"; + if (get_shift_time_time(atoi(preferred), local_time, sizeof(local_time)) == -1) + return 0; + *value = dmstrdup(local_time); + return 0; +} + +int set_IPInterfaceIPv6Prefix_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +int get_IPInterfaceIPv6Prefix_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char local_time[32] = {0}; + char *preferred = ((struct ipv6prefix_args *)data)->ip_6prefixvalid; + *value = "0001-01-01T00:00:00Z"; + if (get_shift_time_time(atoi(preferred), local_time, sizeof(local_time)) == -1) + return 0; + *value = dmstrdup(local_time); + return 0; +} + +int set_IPInterfaceIPv6Prefix_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + break; + } + return 0; +} + +/* + * *** Device.IP.Interface.{i}.Stats. *** + */ int get_ip_interface_statistics_tx_bytes(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { json_object *res, *diag; @@ -2938,16 +3672,194 @@ int get_ip_interface_statistics_rx_discardpackets(char *refparam, struct dmctx * } return 0; } + +int get_ip_interface_statistics_rx_multicastpackets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *res, *diag; + char *lan_name = section_name(((struct ip_args *)data)->ip_sec), *device= NULL; + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", lan_name, String}}, 1, &res); + device = dmjson_get_value(res, 1, "device"); + if(device) { + dmubus_call("network.device", "status", UBUS_ARGS{{"name", device, String}}, 1, &diag); + DM_ASSERT(diag, *value = ""); + *value = dmjson_get_value(diag, 2, "statistics", "multicast"); + } + return 0; +} + +/* + * *** Device.IP.Interface.{i}.TWAMPReflector.{i}. *** + */ +int get_IPInterfaceTWAMPReflector_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "enable", value); + return 0; +} + +int set_IPInterfaceTWAMPReflector_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + unsigned char b; + struct uci_section *s; + char *type, *interface, *device, *id, *ipv4addr = ""; + json_object *res, *jobj; + + switch (action) { + case VALUECHECK: + if (string_to_bool(value, &b)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + if(b) { + dmuci_get_value_by_section_string((struct uci_section *)data, "interface", &interface); + dmuci_get_value_by_section_string((struct uci_section *)data, "id", &id); + dmuci_set_value_by_section((struct uci_section *)data, "enable", "1"); + dmuci_set_value("cwmp_twamp", "twamp", "id", id); + uci_foreach_sections("network", "interface", s) { + if(strcmp(section_name(s), interface) != 0) + continue; + dmuci_get_value_by_section_string(s, "ipaddr", &ipv4addr); + break; + } + if (ipv4addr[0] == '\0') { + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); + if (res) + { + jobj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv4-address"); + ipv4addr = dmjson_get_value(jobj, 1, "address"); + if (ipv4addr[0] == '\0') + dmuci_set_value_by_section((struct uci_section *)data, "ip_version", "6"); + else + dmuci_set_value_by_section((struct uci_section *)data, "ip_version", "4"); + } + } + else + dmuci_set_value_by_section((struct uci_section *)data, "ip_version", "4"); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); + if (res) + { + device = dmjson_get_value(res, 1, "device"); + dmuci_set_value_by_section((struct uci_section *)data, "device", device); + } + } else { + dmuci_set_value_by_section((struct uci_section *)data, "enable", "0"); + } + break; + } + return 0; +} + +int get_IPInterfaceTWAMPReflector_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *enable; + dmuci_get_value_by_section_string((struct uci_section *)data, "enable", &enable); + if(strcmp(enable, "1")==0) + *value = "Active"; + else + *value = "Disabled"; + return 0; +} + +int get_IPInterfaceTWAMPReflector_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "twamp_alias", value); + return 0; +} + +int set_IPInterfaceTWAMPReflector_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + dmuci_set_value_by_section((struct uci_section *)data, "twamp_alias", value); + break; + } + return 0; +} + +int get_IPInterfaceTWAMPReflector_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "port", value); + return 0; +} + +int set_IPInterfaceTWAMPReflector_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + dmuci_set_value_by_section((struct uci_section *)data, "port", value); + break; + } + return 0; +} + +int get_IPInterfaceTWAMPReflector_MaximumTTL(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "max_ttl", value); + return 0; +} + +int set_IPInterfaceTWAMPReflector_MaximumTTL(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + dmuci_set_value_by_section((struct uci_section *)data, "max_ttl", value); + break; + } + return 0; +} + +int get_IPInterfaceTWAMPReflector_IPAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "ip_list", value); + return 0; +} + +int set_IPInterfaceTWAMPReflector_IPAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + dmuci_set_value_by_section((struct uci_section *)data, "ip_list", value); + break; + } + return 0; +} + +int get_IPInterfaceTWAMPReflector_PortAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string((struct uci_section *)data, "port_list", value); + return 0; +} + +int set_IPInterfaceTWAMPReflector_PortAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + switch (action) { + case VALUECHECK: + break; + case VALUESET: + dmuci_set_value_by_section((struct uci_section *)data, "port_list", value); + break; + } + return 0; +} + /************************************************************* * GET & SET ALIAS /*************************************************************/ -int get_ip_int_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +int get_IPInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "ip_int_alias", value); return 0; } -int set_ip_int_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +int set_IPInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { switch (action) { case VALUECHECK: @@ -2986,32 +3898,72 @@ int set_ipv4_alias(char *refparam, struct dmctx *ctx, void *data, char *instance return 0; } -int get_ipv6_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +int get_IPInterfaceIPv6Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { struct uci_section *dmmap_section; + char *name; - get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(((struct ip_args *)data)->ip_sec), &dmmap_section); - dmuci_get_value_by_section_string(dmmap_section, "ipv6_alias", value); + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6", "ipv6_instance", instance, dmmap_section) { + dmuci_get_value_by_section_string(dmmap_section, "section_name", &name); + if(strcmp(name, section_name(((struct ipv6_args *)data)->ip_sec)) == 0) + dmuci_get_value_by_section_string(dmmap_section, "ipv6_alias", value); + } return 0; } -int set_ipv6_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +int set_IPInterfaceIPv6Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - char *proto; + char *proto, *name; struct uci_section *dmmap_section; - get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(((struct ip_args *)data)->ip_sec), &dmmap_section); + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6", "ipv6_instance", instance, dmmap_section) { + dmuci_get_value_by_section_string(dmmap_section, "section_name", &name); + if(strcmp(name, section_name(((struct ipv6_args *)data)->ip_sec)) == 0) + break; + } switch (action) { case VALUECHECK: return 0; case VALUESET: - dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "proto", &proto); - if(strcmp(proto, "static") == 0) - dmuci_set_value_by_section(dmmap_section, "ipv6_alias", value); + dmuci_set_value_by_section(dmmap_section, "ipv6_alias", value); return 0; } return 0; } + +int get_IPInterfaceIPv6Prefix_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *dmmap_section; + char *name; + + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6prefix", "ipv6prefix_instance", instance, dmmap_section) { + dmuci_get_value_by_section_string(dmmap_section, "section_name", &name); + if(strcmp(name, section_name(((struct ipv6prefix_args *)data)->ip_sec)) == 0) + dmuci_get_value_by_section_string(dmmap_section, "ipv6prefix_alias", value); + } + return 0; +} + +int set_IPInterfaceIPv6Prefix_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *proto, *name; + struct uci_section *dmmap_section; + + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6prefix", "ipv6prefix_instance", instance, dmmap_section) { + dmuci_get_value_by_section_string(dmmap_section, "section_name", &name); + if(strcmp(name, section_name(((struct ipv6prefix_args *)data)->ip_sec)) == 0) + break; + } + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + dmuci_set_value_by_section(dmmap_section, "ipv6prefix_alias", value); + return 0; + } + return 0; +} + /************************************************************* * ADD & DEL OBJ /*************************************************************/ @@ -3138,16 +4090,25 @@ int delete_ipv4(char *refparam, struct dmctx *ctx, void *data, char *instance, u int add_ipv6(char *refparam, struct dmctx *ctx, void *data, char **instancepara) { - char *instance; - struct uci_section *dmmap_section; + struct uci_section *s, *ss; + char *ip, *name, *inst, *curr_inst; - get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(((struct ip_args *)data)->ip_sec), &dmmap_section); - dmuci_get_value_by_section_string(((struct ip_args *)data)->ip_sec, "ipv6_instance", &instance); - *instancepara = update_instance(((struct ip_args *)data)->ip_sec, instance, "ipv6_instance"); - if(instance[0] == '\0') { - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "ipv6_instance", *instancepara); - dmuci_set_value_by_section(dmmap_section, "ip6addr", "::"); - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "proto", "static"); + uci_foreach_sections("network", "interface", s) { + if(strcmp(section_name(s), section_name(((struct ipv6_args *)data)->ip_sec)) != 0) + continue; + dmuci_get_value_by_section_string(s, "ip6addr", &ip); + break; + } + if(ip[0] == '\0') { + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6", "section_name", section_name(((struct ipv6_args *)data)->ip_sec), s) { + dmuci_get_value_by_section_string(s, "ipv6_instance", &inst); + } + dmasprintf(&curr_inst, "%d", atoi(inst)+1); + dmuci_set_value_by_section(((struct ipv6_args *)data)->ip_sec, "ip6addr", "::"); + dmuci_set_value_by_section(((struct ipv6_args *)data)->ip_sec, "proto", "static"); + DMUCI_ADD_SECTION(icwmpd, "dmmap_network", "ipv6", &ss, &name); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, ss, "section_name", section_name(((struct ipv6_args *)data)->ip_sec)); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, ss, "ipv6_instance", curr_inst); } return 0; } @@ -3156,12 +4117,12 @@ int delete_ipv6(char *refparam, struct dmctx *ctx, void *data, char *instance, u { struct uci_section *dmmap_section; - get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(((struct ip_args *)data)->ip_sec), &dmmap_section); + get_dmmap_section_of_config_section("dmmap_network", "ipv6", section_name(((struct ipv6_args *)data)->ip_sec), &dmmap_section); switch (del_action) { case DEL_INST: - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "ip6addr", ""); + dmuci_set_value_by_section(((struct ipv6_args *)data)->ip_sec, "ip6addr", ""); dmuci_set_value_by_section(dmmap_section, "ipv6_instance", ""); - dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "proto", ""); + dmuci_set_value_by_section(((struct ipv6_args *)data)->ip_sec, "proto", ""); break; case DEL_ALL: return FAULT_9005; @@ -3169,11 +4130,125 @@ int delete_ipv6(char *refparam, struct dmctx *ctx, void *data, char *instance, u return 0; } +int add_ipv6_prefix(char *refparam, struct dmctx *ctx, void *data, char **instancepara) +{ + struct uci_section *s, *ss; + char *ip, *name, *inst, *curr_inst; + + uci_foreach_sections("network", "interface", s) { + if(strcmp(section_name(s), section_name(((struct ipv6prefix_args *)data)->ip_sec)) != 0) + continue; + dmuci_get_value_by_section_string(s, "ip6prefix", &ip); + break; + } + if(ip[0] == '\0') { + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6prefix", "section_name", section_name(((struct ipv6prefix_args *)data)->ip_sec), s) { + dmuci_get_value_by_section_string(s, "ipv6prefix_instance", &inst); + } + dmasprintf(&curr_inst, "%d", atoi(inst)+1); + dmuci_set_value_by_section(((struct ip_args *)data)->ip_sec, "ip6prefix", "::"); + dmuci_set_value_by_section(((struct ipv6prefix_args *)data)->ip_sec, "proto", "static"); + DMUCI_ADD_SECTION(icwmpd, "dmmap_network", "ipv6prefix", &ss, &name); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, ss, "section_name", section_name(((struct ipv6prefix_args *)data)->ip_sec)); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, ss, "ipv6prefix_instance", curr_inst); + } + return 0; +} + +int delete_ipv6_prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + struct uci_section *dmmap_section; + + get_dmmap_section_of_config_section("dmmap_network", "ipv6prefix", section_name(((struct ipv6prefix_args *)data)->ip_sec), &dmmap_section); + switch (del_action) { + case DEL_INST: + dmuci_set_value_by_section(((struct ipv6prefix_args *)data)->ip_sec, "ip6prefix", ""); + dmuci_set_value_by_section(dmmap_section, "ipv6prefix_instance", ""); + dmuci_set_value_by_section(((struct ipv6prefix_args *)data)->ip_sec, "proto", ""); + break; + case DEL_ALL: + return FAULT_9005; + } + return 0; +} + +static char *get_last_instance_with_option(char *package, char *section, char *option, char *val, char *opt_inst) +{ + struct uci_section *s; + char *inst = NULL; + + uci_foreach_option_eq(package, section, option, val, s) { + inst = update_instance(s, inst, opt_inst); + } + return inst; +} + +static char *get_last_id(char *package, char *section) +{ + struct uci_section *s; + char *id; + int cnt = 0; + + uci_foreach_sections(package, section, s) { + cnt++; + } + dmasprintf(&id, "%d", cnt+1); + return id; +} + +int addObjIPInterfaceTWAMPReflector(char *refparam, struct dmctx *ctx, void *data, char **instance) +{ + struct uci_section *connection; + char *value1, *last_inst, *id; + + last_inst = get_last_instance_with_option("cwmp_twamp", "twamp_refector", "interface", section_name(((struct ip_args *)data)->ip_sec), "twamp_inst"); + id = get_last_id("cwmp_twamp", "twamp_refector"); + dmuci_add_section("cwmp_twamp", "twamp_refector", &connection, &value1); + dmasprintf(instance, "%d", last_inst?atoi(last_inst)+1:1); + dmuci_set_value_by_section(connection, "twamp_inst", *instance); + dmuci_set_value_by_section(connection, "id", id); + dmuci_set_value_by_section(connection, "enable", "0"); + dmuci_set_value_by_section(connection, "interface", section_name(((struct ip_args *)data)->ip_sec)); + dmuci_set_value_by_section(connection, "port", "862"); + dmuci_set_value_by_section(connection, "max_ttl", "1"); + return 0; +} + +int delObjIPInterfaceTWAMPReflector(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) +{ + int found = 0; + struct uci_section *s, *ss = NULL; + char *interface; + struct uci_section *section = (struct uci_section *)data; + + switch (del_action) { + case DEL_INST: + dmuci_delete_by_section(section, NULL, NULL); + return 0; + case DEL_ALL: + uci_foreach_sections("cwmp_twamp", "twamp_refector", s) { + dmuci_get_value_by_section_string(s, "interface", &interface); + if(strcmp(interface, section_name(((struct ip_args *)data)->ip_sec)) != 0) + continue; + if (found != 0) { + dmuci_delete_by_section(ss, NULL, NULL); + } + ss = s; + found++; + } + if (ss != NULL) { + dmuci_delete_by_section(ss, NULL, NULL); + } + return 0; + } + return 0; +} + /************************************************************************** * LINKER ***************************************************************************/ int get_linker_ip_interface(char *refparam, struct dmctx *dmctx, void *data, char *instance, char **linker) { - if(((struct ip_args *)data)->ip_sec) { + if(data && ((struct ip_args *)data)->ip_sec) { dmasprintf(linker,"%s", section_name(((struct ip_args *)data)->ip_sec)); return 0; } else { @@ -3181,15 +4256,24 @@ int get_linker_ip_interface(char *refparam, struct dmctx *dmctx, void *data, cha return 0; } } + +int get_linker_ipv6_prefix(char *refparam, struct dmctx *dmctx, void *data, char *instance, char **linker) { + if(((struct ipv6prefix_args *)data)->ip_sec) { + dmasprintf(linker,"%s", get_child_prefix_linker(section_name(((struct ipv6prefix_args *)data)->ip_sec))); + return 0; + } else { + *linker = ""; + return 0; + } +} + /************************************************************* * ENTRY METHOD /*************************************************************/ int browseIPIfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - struct uci_section *net_sec = NULL; char *ip_int = NULL, *ip_int_last = NULL; - char *type, *ipv4addr = "", *ipv6addr = "", *proto, *inst; - json_object *res, *jobj; + char *type, *ipv4addr = ""; struct ip_args curr_ip_args = {0}; struct dmmap_dup *p; LIST_HEAD(dup_list); @@ -3199,34 +4283,18 @@ int browseIPIfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, dmuci_get_value_by_section_string(p->config_section, "type", &type); if (strcmp(type, "alias") == 0 || strcmp(section_name(p->config_section), "loopback")==0) continue; + + /* IPv4 address */ dmuci_get_value_by_section_string(p->config_section, "ipaddr", &ipv4addr); - if (ipv4addr[0] == '\0') { - dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", section_name(p->config_section), String}}, 1, &res); - if (res) - { - jobj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv4-address"); - ipv4addr = dmjson_get_value(jobj, 1, "address"); - } - } - dmuci_get_value_by_section_string(p->config_section, "ip6addr", &ipv6addr); - if (ipv6addr[0] == '\0') { - dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", section_name(p->config_section), String}}, 1, &res); - if (res) - { - jobj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv6-address"); - ipv6addr = dmjson_get_value(jobj, 1, "address"); - } - } - dmuci_get_value_by_section_string(p->config_section, "proto", &proto); - dmuci_get_value_by_section_string(p->config_section, "ip_int_instance", &inst); - if (ipv4addr[0] == '\0' && ipv6addr[0] == '\0' && strcmp(proto, "dhcp") != 0 && strcmp(proto, "dhcpv6") != 0 && strcmp(proto, "relay") != 0 && strcmp(inst, "") == 0 && strcmp(type, "bridge") != 0) { - continue; - } - init_ip_args(&curr_ip_args, p->config_section, ipv4addr, ipv6addr); + if (ipv4addr[0] == '\0') + ipv4addr = ubus_call_get_value(section_name(p->config_section), "ipv4-address", "address"); + + init_ip_args(&curr_ip_args, p->config_section, ipv4addr); ip_int = handle_update_instance(1, dmctx, &ip_int_last, update_instance_alias, 3, p->dmmap_section, "ip_int_instance", "ip_int_alias"); if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_ip_args, ip_int) == DM_STOP) break; } + free_dmmap_config_dup_list(&dup_list); return 0; } @@ -3245,26 +4313,164 @@ end: return 0; } +static struct uci_section *update_dmmap_network_ipv6(char *curr_inst, char *section_name) +{ + struct uci_section *s = NULL; + char *inst, *name; + + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6", "section_name", section_name, s) { + dmuci_get_value_by_section_string(s, "ipv6_instance", &inst); + if(strcmp(curr_inst, inst) == 0) + return s; + } + if (!s) { + DMUCI_ADD_SECTION(icwmpd, "dmmap_network", "ipv6", &s, &name); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, s, "section_name", section_name); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, s, "ipv6_instance", curr_inst); + } + return s; +} + int browseIfaceIPv6Inst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - char *ipv6_inst = NULL, *ipv6_inst_last = NULL; - struct uci_section *dmmap_section; + struct uci_section *s; + char *ipv6_int = NULL, *ipv6_int_last = NULL, *ipv6addr = "", *ipv6mask = "", *ipv6_preferred = "", *ipv6_valid = "", buf[4]=""; + struct ipv6_args curr_ipv6_args = {0}; + json_object *res, *jobj, *jobj1; + int entries = 0; - get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(((struct ip_args *)prev_data)->ip_sec), &dmmap_section); - if (((struct ip_args *)prev_data)->ip_6address[0] != '\0') { - ipv6_inst = handle_update_instance(2, dmctx, &ipv6_inst_last, update_instance_alias, 3, dmmap_section, "ipv6_instance", "ipv6_alias"); - if (DM_LINK_INST_OBJ(dmctx, parent_node, prev_data, ipv6_inst) == DM_STOP) + if(prev_data && ((struct ip_args *)prev_data)->ip_sec) { + dmuci_get_value_by_section_string(((struct ip_args *)prev_data)->ip_sec, "ip6addr", &ipv6addr); + dmuci_get_value_by_section_string(((struct ip_args *)prev_data)->ip_sec, "adv_preferred_lifetime", &ipv6_preferred); + dmuci_get_value_by_section_string(((struct ip_args *)prev_data)->ip_sec, "adv_valid_lifetime", &ipv6_valid); + if (ipv6addr[0] == '\0') { + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", section_name(((struct ip_args *)prev_data)->ip_sec), String}}, 1, &res); + while (res) { + jobj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv6-prefix-assignment"); + if(jobj) { + jobj1 = dmjson_get_obj(jobj, 1, "local-address"); + if(jobj1) { + ipv6addr = dmjson_get_value(jobj1, 1, "address"); + ipv6mask = dmjson_get_value(jobj1, 1, "mask"); + goto browse; + } + } + jobj = dmjson_select_obj_in_array_idx(res, entries, 1, "ipv6-address"); + if(jobj) { + ipv6addr = dmjson_get_value(jobj, 1, "address"); + ipv6mask = dmjson_get_value(jobj, 1, "mask"); + if (ipv6_preferred[0] == '\0') + ipv6_preferred = dmjson_get_value(jobj, 1, "preferred"); + if (ipv6_valid[0] == '\0') + ipv6_valid = dmjson_get_value(jobj, 1, "valid"); + entries++; + sprintf(buf, "%d", entries); + s = update_dmmap_network_ipv6(buf, section_name(((struct ip_args *)prev_data)->ip_sec)); + init_ipv6_args(&curr_ipv6_args, ((struct ip_args *)prev_data)->ip_sec, ipv6addr, ipv6mask, ipv6_preferred, ipv6_valid); + ipv6_int = handle_update_instance(1, dmctx, &ipv6_int_last, update_instance_alias, 3, s, "ipv6_instance", "ipv6_alias"); + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_ipv6_args, ipv6_int) == DM_STOP) + goto end; + } else + goto end; + } + } +browse: + s = update_dmmap_network_ipv6("1", section_name(((struct ip_args *)prev_data)->ip_sec)); + init_ipv6_args(&curr_ipv6_args, ((struct ip_args *)prev_data)->ip_sec, ipv6addr, ipv6mask, ipv6_preferred, ipv6_valid); + ipv6_int = handle_update_instance(1, dmctx, &ipv6_int_last, update_instance_alias, 3, s, "ipv6_instance", "ipv6_alias"); + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_ipv6_args, ipv6_int) == DM_STOP) goto end; } end: return 0; } + +static struct uci_section *update_dmmap_network_ipv6prefix(char *curr_inst, char *section_name) +{ + struct uci_section *s = NULL; + char *inst, *name; + + uci_path_foreach_option_eq(icwmpd, "dmmap_network", "ipv6prefix", "section_name", section_name, s) { + dmuci_get_value_by_section_string(s, "ipv6prefix_instance", &inst); + if(strcmp(curr_inst, inst) == 0) + return s; + } + if (!s) { + DMUCI_ADD_SECTION(icwmpd, "dmmap_network", "ipv6prefix", &s, &name); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, s, "section_name", section_name); + DMUCI_SET_VALUE_BY_SECTION(icwmpd, s, "ipv6prefix_instance", curr_inst); + } + return s; +} + +int browseIfaceIPv6PrefixInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *s; + char *ipv6prefix_int = NULL, *ipv6prefix_int_last = NULL, *ipv6prefixaddr = "", *ipv6prefixmask = "", *ipv6prefix_preferred = "", *ipv6prefix_valid = "", buf[4] = ""; + struct ipv6prefix_args curr_ipv6prefix_args = {0}; + json_object *res, *jobj; + int entries = 0; + + if(prev_data && ((struct ip_args *)prev_data)->ip_sec) { + dmuci_get_value_by_section_string(((struct ip_args *)prev_data)->ip_sec, "ip6prefix", &ipv6prefixaddr); + if (ipv6prefixaddr[0] == '\0') { + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", section_name(((struct ip_args *)prev_data)->ip_sec), String}}, 1, &res); + while (res) { + jobj = dmjson_select_obj_in_array_idx(res, 0, 1, "ipv6-prefix-assignment"); + if(jobj) { + ipv6prefixaddr = dmjson_get_value(jobj, 1, "address"); + ipv6prefixmask = dmjson_get_value(jobj, 1, "mask"); + ipv6prefix_preferred = dmjson_get_value(jobj, 1, "preferred"); + ipv6prefix_valid = dmjson_get_value(jobj, 1, "valid"); + goto browse; + } + jobj = dmjson_select_obj_in_array_idx(res, entries, 1, "ipv6-prefix"); + if(jobj) { + ipv6prefixaddr = dmjson_get_value(jobj, 1, "address"); + ipv6prefixmask = dmjson_get_value(jobj, 1, "mask"); + ipv6prefix_preferred = dmjson_get_value(jobj, 1, "preferred"); + ipv6prefix_valid = dmjson_get_value(jobj, 1, "valid"); + entries++; + sprintf(buf, "%d", entries); + s = update_dmmap_network_ipv6prefix(buf, section_name(((struct ip_args *)prev_data)->ip_sec)); + init_ipv6prefix_args(&curr_ipv6prefix_args, ((struct ip_args *)prev_data)->ip_sec, ipv6prefixaddr, ipv6prefixmask, ipv6prefix_preferred, ipv6prefix_valid); + ipv6prefix_int = handle_update_instance(1, dmctx, &ipv6prefix_int_last, update_instance_alias, 3, s, "ipv6prefix_instance", "ipv6prefix_alias"); + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_ipv6prefix_args, ipv6prefix_int) == DM_STOP) + goto end; + } else + goto end; + } + } +browse: + s = update_dmmap_network_ipv6prefix("1", section_name(((struct ip_args *)prev_data)->ip_sec)); + init_ipv6prefix_args(&curr_ipv6prefix_args, ((struct ip_args *)prev_data)->ip_sec, ipv6prefixaddr, ipv6prefixmask, ipv6prefix_preferred, ipv6prefix_valid); + ipv6prefix_int = handle_update_instance(1, dmctx, &ipv6prefix_int_last, update_instance_alias, 3, s, "ipv6prefix_instance", "ipv6prefix_alias"); + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_ipv6prefix_args, ipv6prefix_int) == DM_STOP) + goto end; + } +end: + return 0; +} + +int browseIPInterfaceTWAMPReflectorInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) +{ + struct uci_section *s = NULL; + char *twamp_inst = NULL, *twamp_inst_last = NULL; + + uci_foreach_option_eq("cwmp_twamp", "twamp_refector", "interface", section_name(((struct ip_args *)prev_data)->ip_sec), s) + { + twamp_inst = handle_update_instance(2, dmctx, &twamp_inst_last, update_instance_alias, 3, (void *)s, "twamp_inst", "twamp_alias"); + if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)s, twamp_inst) == DM_STOP) + break; + } + return 0; +} + int browseIPDiagnosticsTraceRouteRouteHopsInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { struct uci_section *s = NULL; char *instance, *idx_last = NULL; - int id = 0; uci_foreach_sections_state("cwmp", "RouteHops", s) { @@ -3279,7 +4485,6 @@ int browseIPDiagnosticsDownloadDiagnosticsPerConnectionResultInst(struct dmctx * { struct uci_section *s = NULL; char *instance, *idx_last = NULL; - int id = 0; uci_foreach_sections_state("cwmp", "DownloadPerConnection", s) { @@ -3294,7 +4499,6 @@ int browseIPDiagnosticsUploadDiagnosticsPerConnectionResultInst(struct dmctx *dm { struct uci_section *s = NULL; char *instance, *idx_last = NULL; - int id = 0; uci_foreach_sections_state("cwmp", "UploadPerConnection", s) { diff --git a/dm/dmtree/tr181/ip.h b/dm/dmtree/tr181/ip.h index 7156e5f..e68b64e 100644 --- a/dm/dmtree/tr181/ip.h +++ b/dm/dmtree/tr181/ip.h @@ -17,14 +17,34 @@ struct ip_args { struct uci_section *ip_sec; char *ip_4address; +}; + +struct ipv6_args +{ + struct uci_section *ip_sec; char *ip_6address; + char *ip_6mask; + char *ip_6preferred; + char *ip_6valid; +}; + +struct ipv6prefix_args +{ + struct uci_section *ip_sec; + char *ip_6prefixaddress; + char *ip_6prefixmask; + char *ip_6prefixpreferred; + char *ip_6prefixvalid; }; extern DMOBJ tIPObj[]; +extern DMLEAF tIPParams[]; extern DMOBJ tInterfaceObj[]; extern DMLEAF tIPv4Params[]; extern DMLEAF tIPv6Params[]; +extern DMLEAF tIPv6PrefixParams[]; extern DMLEAF tIPInterfaceStatsParams[]; +extern DMLEAF tIPInterfaceTWAMPReflectorParams[]; extern DMLEAF tIPintParams[]; extern DMOBJ tDiagnosticObj[]; extern DMLEAF tIPDiagnosticsParams[]; @@ -44,11 +64,15 @@ extern DMLEAF tIPDiagnosticsServerSelectionDiagnosticsParams[]; unsigned char get_ipv4_finform(char *refparam, struct dmctx *dmctx, void *data, char *instance); unsigned char get_ipv6_finform(char *refparam, struct dmctx *dmctx, void *data, char *instance); + int get_linker_ip_interface(char *refparam, struct dmctx *dmctx, void *data, char *instance, char **linker); +int get_linker_ipv6_prefix(char *refparam, struct dmctx *dmctx, void *data, char *instance, char **linker); int browseIPIfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); int browseIfaceIPv4Inst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); int browseIfaceIPv6Inst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); +int browseIfaceIPv6PrefixInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); +int browseIPInterfaceTWAMPReflectorInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); int browseIPDiagnosticsTraceRouteRouteHopsInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); int browseIPDiagnosticsDownloadDiagnosticsPerConnectionResultInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); int browseIPDiagnosticsUploadDiagnosticsPerConnectionResultInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance); @@ -59,39 +83,112 @@ int add_ipv4(char *refparam, struct dmctx *ctx, void *data, char **instancepara) int delete_ipv4(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action); int add_ipv6(char *refparam, struct dmctx *ctx, void *data, char **instancepara); int delete_ipv6(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action); +int add_ipv6_prefix(char *refparam, struct dmctx *ctx, void *data, char **instance); +int delete_ipv6_prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action); +int addObjIPInterfaceTWAMPReflector(char *refparam, struct dmctx *ctx, void *data, char **instance); +int delObjIPInterfaceTWAMPReflector(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action); int get_diag_enable_true(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_diag_enable_false(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_interface_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_interface_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_interface_name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_int_lower_layer(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IP_IPv4Capable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IP_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IP_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IP_IPv4Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IP_IPv6Capable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IP_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IP_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IP_IPv6Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IP_ULAPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IP_ULAPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IP_InterfaceNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); + int get_ipv4_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_ipv4_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); int get_firewall_enabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_firewall_enabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); int get_ipv4_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_ipv4_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); int get_ipv4_netmask(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_ipv4_netmask(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); int get_ipv4_addressing_type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ipv6_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ipv6_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ipv6_addressing_type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_diagnostics_state(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_protocolversion(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_host(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_repetition_number(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_timeout(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_block_size(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_DSCP(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_success_count(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_failure_count(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_average_response_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_min_response_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_max_response_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_AverageResponseTimeDetailed(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_MinimumResponseTimeDetailed(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int get_ip_ping_MaximumResponseTimeDetailed(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_ipv4_addressing_type(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); + +int get_IPInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_IPv4Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_IPv6Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterface_LastChange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_Router(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_Router(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_MaxMTUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_MaxMTUSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_Type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterface_Loopback(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterface_Loopback(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterface_IPv4AddressNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterface_IPv6AddressNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterface_IPv6PrefixNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterface_TWAMPReflectorNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); + +int get_IPInterfaceIPv6Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Address_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Address_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterfaceIPv6Address_IPAddressStatus(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterfaceIPv6Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Address_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Address_IPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Address_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterfaceIPv6Address_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Address_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Address_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Address_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Address_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Address_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); + +int get_IPInterfaceIPv6Prefix_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Prefix_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterfaceIPv6Prefix_PrefixStatus(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterfaceIPv6Prefix_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Prefix_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_Prefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Prefix_Origin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterfaceIPv6Prefix_StaticType(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_StaticType(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Prefix_ParentPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_ParentPrefix(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Prefix_ChildPrefixBits(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_ChildPrefixBits(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Prefix_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_PreferredLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceIPv6Prefix_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceIPv6Prefix_ValidLifetime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); + +int get_IPInterfaceTWAMPReflector_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceTWAMPReflector_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceTWAMPReflector_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_IPInterfaceTWAMPReflector_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceTWAMPReflector_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceTWAMPReflector_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceTWAMPReflector_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceTWAMPReflector_MaximumTTL(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceTWAMPReflector_MaximumTTL(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceTWAMPReflector_IPAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceTWAMPReflector_IPAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_IPInterfaceTWAMPReflector_PortAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int set_IPInterfaceTWAMPReflector_PortAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); + int get_ip_interface_statistics_tx_bytes(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_ip_interface_statistics_rx_bytes(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_ip_interface_statistics_tx_packets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); @@ -100,27 +197,32 @@ int get_ip_interface_statistics_tx_errors(char *refparam, struct dmctx *ctx, voi int get_ip_interface_statistics_rx_errors(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_ip_interface_statistics_tx_discardpackets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_ip_interface_statistics_rx_discardpackets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_interface_statistics_rx_multicastpackets(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); -int set_ip_int_lower_layer(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ip_int_lower_layer(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv4_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_firewall_enabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv4_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv4_netmask(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv4_addressing_type(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv6_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv6_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv6_addressing_type(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_diagnostics_state(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_diagnostics_state(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_protocolversion(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_protocolversion(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_host(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_host(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_repetition_number(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_repetition_number(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_timeout(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_timeout(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_block_size(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_block_size(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_DSCP(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_ip_ping_DSCP(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ipv6_addressing_type(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); -int set_ip_interface_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); +int get_ip_ping_success_count(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_ping_failure_count(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_ping_average_response_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_ping_min_response_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_ping_max_response_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_ping_AverageResponseTimeDetailed(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_ping_MinimumResponseTimeDetailed(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); +int get_ip_ping_MaximumResponseTimeDetailed(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_IPDiagnosticsTraceRoute_DiagnosticsState(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int set_IPDiagnosticsTraceRoute_DiagnosticsState(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action); @@ -292,4 +394,5 @@ int get_IPDiagnosticsServerSelectionDiagnostics_FastestHost(char *refparam, stru int get_IPDiagnosticsServerSelectionDiagnostics_MinimumResponseTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_IPDiagnosticsServerSelectionDiagnostics_AverageResponseTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); int get_IPDiagnosticsServerSelectionDiagnostics_MaximumResponseTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value); + #endif diff --git a/init/icwmp_twampd b/init/icwmp_twampd new file mode 100644 index 0000000..d20c91e --- /dev/null +++ b/init/icwmp_twampd @@ -0,0 +1,56 @@ +#!/bin/sh /etc/rc.common +#TWAMP Reflector software +# Copyright (C) 2019 iopsys Software Solutions AB +#Author: Amin Ben Ramdhane + +START=99 +STOP=10 + +USE_PROCD=1 +PROG="/usr/sbin/icwmp_twampd" + +start_service() { + local id=`uci -q get cwmp_twamp.twamp.id` + local connection=`uci show cwmp_twamp | grep "cwmp_twamp.@twamp_refector.*id=\'$id\'" | cut -d "." -f 2` + local enable=`uci -q get cwmp_twamp.$connection.enable` + local interface=`uci -q get cwmp_twamp.$connection.interface` + local port=`uci -q get cwmp_twamp.$connection.port` + local port_list=`uci -q get cwmp_twamp.$connection.port_list` + port_list=`echo $port_list | tr "," " "` + if [ "$enable" = "1" ]; then + if [ $interface = "wan" ]; then + for str in $port_list; do + if [ "${str/-}" != "$str" ] ; then + str=`echo $str | tr "-" ":"` + fi + iptables -I zone_wan_input -p udp --dport "$str" -j ACCEPT -m comment --comment "Open UDP allowed port" + iptables -I zone_wan_input -p tcp --dport "$port" -j ACCEPT -m comment --comment "Open TCP allowed port" + done + fi + procd_open_instance + procd_set_param command "$PROG" + procd_set_param respawn "3" "7" "0" + procd_close_instance + else + if [ $interface = "wan" ]; then + if [ "${str/-}" != "$str" ] ; then + str=`echo $str | tr "-" ":"` + fi + iptables -I zone_wan_input -p udp --dport "$str" -j REJECT -m comment --comment "Close UDP allowed port" + iptables -I zone_wan_input -p tcp --dport "$port" -j REJECT -m comment --comment "Close TCP allowed port" + fi + fi +} + +boot() { + start +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger cwmp_twamp +} diff --git a/twamp/twamp.c b/twamp/twamp.c new file mode 100644 index 0000000..7f37a45 --- /dev/null +++ b/twamp/twamp.c @@ -0,0 +1,857 @@ +/* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Copyright (C) 2019 iopsys Software Solutions AB +* Author: Amin Ben Ramdhane +* +* Name: Emma Mirică +* Project: TWAMP Protocol +* Class: OSS +* Email: emma.mirica@cti.pub.ro +* Contributions: stephanDB +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "twamp.h" +#include "twamplog.h" +#include "twampuci.h" + +struct twamp_config cur_twamp_conf = {0}; +TWAMPTimestamp ZeroT = { 0, 0 }; + +struct active_session { + int socket; + RequestSession req; + uint16_t server_oct; + uint32_t sid_addr; + TWAMPTimestamp sid_time; + uint32_t sid_rand; + uint32_t seq_nb; + uint32_t snd_nb; + uint32_t fw_msg; + uint32_t fw_lst_msg; +}; + +struct client_info { + ClientStatus status; + int socket; + struct sockaddr_in addr; + struct sockaddr_in6 addr6; + int mode; + int sess_no; + struct timeval shutdown_time; + struct active_session sessions[MAX_SESSIONS_PER_CLIENT]; +}; + +static int fd_max = 0; +static enum Mode authmode = kModeUnauthenticated; +static int used_sockets = 0; +static fd_set read_fds; +static int socket_family = AF_INET; + +static int check_ipv4_address(char *ip, char *maskstr, char *address) +{ + struct sockaddr_in sa = {0}; + unsigned long netaddress, maxaddress; + unsigned long mask = ~((1 << (32 - atoi(maskstr))) - 1); + inet_pton(AF_INET, address, &(sa.sin_addr)); + netaddress = (ntohl(sa.sin_addr.s_addr) & mask); + sa.sin_addr.s_addr = 0; + inet_pton(AF_INET, ip, &(sa.sin_addr)); + maxaddress = (ntohl(sa.sin_addr.s_addr) & mask); + if (maxaddress == netaddress) + return 1; + return 0; +} + +static char *check_ipv6_address_active(char *ip) +{ + unsigned char buf[sizeof(struct in6_addr)]; + char str[INET6_ADDRSTRLEN], *res; + int s; + + s = inet_pton(AF_INET6, ip, buf); + if (s <= 0) { + if (s == 0) + twamp_log(SCRIT, "Not in presentation format"); + else + twamp_log(SCRIT, "inet_pton"); + return ""; + } + if (inet_ntop(AF_INET6, buf, str, INET6_ADDRSTRLEN) == NULL) { + twamp_log(SCRIT, "inet_ntop"); + return ""; + } + res = strdup(str); + return res; +} + +static int check_ipv6_address(char *ip, char *maskstr, char *address) +{ + struct sockaddr_in6 sa = {0}; + unsigned long netaddress, maxaddress; + unsigned long mask = ~((1 << (128 - atoi(maskstr))) - 1); + inet_pton(AF_INET6, address, &(sa.sin6_addr)); + netaddress = (ntohl(sa.sin6_addr.s6_addr) & mask); + inet_pton(AF_INET6, ip, &(sa.sin6_addr)); + maxaddress = (ntohl(sa.sin6_addr.s6_addr) & mask); + if (maxaddress == netaddress) + return 1; + return 0; +} + +static int check_ip_address_allowed(char *address) +{ + char *pch, *spch, *ip, *mask, *str, *addr; + + for (pch = strtok_r(cur_twamp_conf.ip_list, ",", &spch); pch != NULL; pch = strtok_r(NULL, ",", &spch)) + { + if(strstr(pch, ".")) { + if(strstr(pch, "/")) { + ip = strtok_r(pch, "/", &str); + mask = strtok_r(NULL, "", &str); + if(check_ipv4_address(ip, mask, address)) + return 1; + continue; + } + if (strcmp(pch, address) == 0) + return 1; + } else { + addr = check_ipv6_address_active(address); + if(strstr(pch, "/")) { + ip = strtok_r(pch, "/", &str); + mask = strtok_r(NULL, "", &str); + ip = check_ipv6_address_active(ip); + if(check_ipv6_address(ip, mask, addr)) + return 1; + continue; + } + pch = check_ipv6_address_active(pch); + if (strcmp(pch, addr) == 0) + return 1; + } + } + return 0; +} + +static int check_port_allowed(int port) +{ + char *pch, *spch, *min, *max, *str; + + for (pch = strtok_r(cur_twamp_conf.port_list, ",", &spch); pch != NULL; pch = strtok_r(NULL, ",", &spch)) + { + if(strstr(pch, "-")) { + min = strtok_r(pch, "-", &str); + max = strtok_r(NULL, "", &str); + if(port >= atoi(min) && port <= atoi(max)) + return 1; + continue; + } + if (port == atoi(pch)) + return 1; + } + return 0; +} + +/* The cleanup_client function will close every connection (TWAMP-Control ot TWAMP-Test that this server has with the client defined by the client_infor + * structure received as a parameter. + */ +static void cleanup_client(struct client_info *client) +{ + char str_client[INET6_ADDRSTRLEN]; + inet_ntop(socket_family, (socket_family == AF_INET6) ? (void*) &(client->addr6.sin6_addr) : (void*) &(client->addr.sin_addr), str_client, sizeof(str_client)); + twamp_log(SINFO, "Cleanup client %s", str_client); + FD_CLR(client->socket, &read_fds); + close(client->socket); + used_sockets--; + int i; + for (i = 0; i < client->sess_no; i++) + /* If socket is -1 the session has already been closed */ + if (client->sessions[i].socket > 0) { + FD_CLR(client->sessions[i].socket, &read_fds); + close(client->sessions[i].socket); + client->sessions[i].socket = -1; + used_sockets--; + } + memset(client, 0, sizeof(struct client_info)); + client->status = kOffline; +} + +/* The TWAMP server can only accept max_clients and it will recycle the positions for the available clients. */ +static int find_empty_client(struct client_info *clients, int max_clients) +{ + int i; + for (i = 0; i < max_clients; i++) + if (clients[i].status == kOffline) + return i; + return -1; +} + +/* Sends a ServerGreeting message to the Control-Client after the TCP connection has been established. */ +static int send_greeting(uint16_t mode_mask, struct client_info *client) +{ + int socket = client->socket; + + char str_client[INET6_ADDRSTRLEN]; /* String for Client IP address */ + inet_ntop(socket_family, (socket_family == AF_INET6) ? (void*) &(client->addr6.sin6_addr) : (void*) &(client->addr.sin_addr), str_client, sizeof(str_client)); + + int i; + ServerGreeting greet; + memset(&greet, 0, sizeof(greet)); + greet.Modes = htonl(client->mode & mode_mask); + for (i = 0; i < 16; i++) + greet.Challenge[i] = rand() % 16; + for (i = 0; i < 16; i++) + greet.Salt[i] = rand() % 16; + greet.Count = htonl(1 << 10); + + int rv = send(socket, &greet, sizeof(greet), 0); + if (rv < 0) { + twamp_log(SCRIT,"Failed to send ServerGreeting message"); + cleanup_client(client); + } else if ((authmode & 0x000F) == 0) { + twamp_log(SCRIT,"Sent ServerGreeting message with Mode 0! Abort"); + cleanup_client(client); + } else { + twamp_log(SINFO,"Sent ServerGreeting message to %s", str_client); + } + return rv; +} + +/* After a ServerGreeting the Control-Client should respond with a SetUpResponse. This function treats this message */ +static int receive_greet_response(struct client_info *client) +{ + int socket = client->socket; + char str_client[INET6_ADDRSTRLEN]; /* String for Client IP address */ + inet_ntop(socket_family, (socket_family == AF_INET6)? (void*) &(client->addr6.sin6_addr) : (void*) &(client->addr.sin_addr), str_client, sizeof(str_client)); + + SetUpResponse resp; + memset(&resp, 0, sizeof(resp)); + int rv = recv(socket, &resp, sizeof(resp), 0); + if (rv <= 32) { + twamp_log(SCRIT,"Failed to receive SetUpResponse"); + cleanup_client(client); + } else { + twamp_log(SINFO, "Received SetUpResponse message from %s with mode %d", str_client, ntohl(resp.Mode)); + if ((ntohl(resp.Mode) & client->mode & 0x000F) == 0) { + twamp_log(SCRIT,"The client does not support any usable Mode"); + rv = 0; + } + client->mode = ntohl(resp.Mode); + } + return rv; +} + +/* Sent a ServerStart message to the Control-Client to endthe TWAMP-Control session establishment phase */ +static int send_start_serv(struct client_info *client, TWAMPTimestamp StartTime) +{ + int socket = client->socket; + + char str_client[INET6_ADDRSTRLEN]; + inet_ntop(socket_family, (socket_family == AF_INET6)? (void*) &(client->addr6.sin6_addr) : (void*) &(client->addr.sin_addr), str_client, sizeof(str_client)); + + ServerStart msg; + memset(&msg, 0, sizeof(msg)); + if ((StartTime.integer == 0) && (StartTime.fractional == 0)) { + msg.Accept = kAspectNotSupported; + } else { + msg.Accept = kOK; + } + msg.StartTime = StartTime; + int rv = send(socket, &msg, sizeof(msg), 0); + if (rv <= 0) { + twamp_log(SCRIT,"Failed to send ServerStart message"); + cleanup_client(client); + } else { + client->status = kConfigured; + twamp_log(SINFO, "ServerStart message sent to %s", str_client); + if (msg.Accept == kAspectNotSupported) { + cleanup_client(client); + } + } + return rv; +} + +/* Sends a StartACK for the StartSessions message */ +static int send_start_ack(struct client_info *client) +{ + char str_client[INET6_ADDRSTRLEN]; + inet_ntop(socket_family, (socket_family == AF_INET6)? (void*) &(client->addr6.sin6_addr) : (void*) &(client->addr.sin_addr), str_client, sizeof(str_client)); + StartACK ack; + memset(&ack, 0, sizeof(ack)); + ack.Accept = kOK; + int rv = send(client->socket, &ack, sizeof(ack), 0); + if (rv <= 0) { + twamp_log(SCRIT,"Failed to send StartACK message"); + } else + twamp_log(SINFO,"StartACK message sent to %s", str_client); + return rv; +} + +/* This function treats the case when a StartSessions is received from the Control-Client to start a number of TWAMP-Test sessions */ +static int receive_start_sessions(struct client_info *client) +{ + int i; + int rv = send_start_ack(client); + if (rv <= 0) + return rv; + + /* Now it can receive packets on the TWAMP-Test sockets */ + for (i = 0; i < client->sess_no; i++) { + FD_SET(client->sessions[i].socket, &read_fds); + if (fd_max < client->sessions[i].socket) + fd_max = client->sessions[i].socket; + } + client->status = kTesting; + return rv; +} + +/* This functions treats the case when a StopSessions is received from the Control-Client to end all the Test sessions. */ +static int receive_stop_sessions(struct client_info *client) +{ + /* If a StopSessions message was received, it can still receive Test packets until the timeout has expired */ + gettimeofday(&client->shutdown_time, NULL); + return 0; +} + +/* Computes the response to a RequestTWSession message */ +static int send_accept_session(struct client_info *client, RequestSession * req) +{ + char str_client[INET6_ADDRSTRLEN]; /* String for Client IP address */ + AcceptSession acc; + memset(&acc, 0, sizeof(acc)); + + inet_ntop(socket_family, (socket_family == AF_INET6)? (void*) &(client->addr6.sin6_addr) : (void*) &(client->addr.sin_addr), str_client, sizeof(str_client)); + + + /* Check if there are any slots available */ + if ((used_sockets < 64) && (client->sess_no < MAX_SESSIONS_PER_CLIENT)) { + int testfd = socket(socket_family, SOCK_DGRAM, 0); + if (testfd < 0) { + twamp_log(SCRIT,"Error opening socket"); + return -1; + } + + int check_time = CHECK_TIMES; + if(socket_family == AF_INET6) { + struct sockaddr_in6 local_addr; + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin6_family = AF_INET6; + local_addr.sin6_addr = in6addr_any; + local_addr.sin6_port = req->ReceiverPort; + + while (check_time-- && bind(testfd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) + local_addr.sin6_port = htons(20000 + rand() % 1000); + + if (check_time > 0) { + req->ReceiverPort = local_addr.sin6_port; + } + } else { + struct sockaddr_in local_addr; + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin_family = AF_INET; + local_addr.sin_addr.s_addr = htonl(INADDR_ANY); + local_addr.sin_port = req->ReceiverPort; + + while (check_time-- && bind(testfd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr)) < 0) + local_addr.sin_port = htons(20000 + rand() % 1000); + + if (check_time > 0) { + req->ReceiverPort = local_addr.sin_port; + } + } + + if (check_time > 0) { + acc.Accept = kOK; + acc.Port = req->ReceiverPort; + client->sessions[client->sess_no].socket = testfd; + client->sessions[client->sess_no].req = *req; + /* SID construction */ + memcpy(acc.SID, &req->ReceiverAddress, 4); + TWAMPTimestamp sidtime = get_timestamp(); + memcpy(&acc.SID[4], &sidtime, 8); + int k; + for (k = 0; k < 4; k++) + acc.SID[12 + k] = rand() % 256; + memcpy(&client->sessions[client->sess_no].sid_addr, &acc.SID, 4); + client->sessions[client->sess_no].sid_time = sidtime; + memcpy(&client->sessions[client->sess_no].sid_rand, &acc.SID[12], 4); + + twamp_log(SINFO, "SID: 0x%04X.%04X.%04X.%04X", + ntohl(client->sessions[client->sess_no].sid_addr), + ntohl(client->sessions[client->sess_no].sid_time.integer), + ntohl(client->sessions[client->sess_no].sid_time.fractional), + ntohl(client->sessions[client->sess_no].sid_rand)); + + /* Set socket options */ + set_socket_option(testfd, cur_twamp_conf.max_ttl); + set_socket_tos(testfd, (client->sessions[client->sess_no].req.TypePDescriptor << 2)); + + client->sess_no++; + + } else { + twamp_log(SINFO, "kTemporaryResourceLimitation: check_time [%d]", check_time); + acc.Accept = kTemporaryResourceLimitation; + acc.Port = 0; + } + + } else { + twamp_log(SINFO, "kTemporaryResourceLimitation: used_sockets [%d], sess_no [%d]", used_sockets, client->sess_no); + acc.Accept = kTemporaryResourceLimitation; + acc.Port = 0; + } + + int rv = send(client->socket, &acc, sizeof(acc), 0); + return rv; +} + +/* This function treats the case when a RequestTWSession is received */ +static int receive_request_session(struct client_info *client, RequestSession * req) +{ + char str_client[INET6_ADDRSTRLEN]; /* String for Client IP address */ + + if(socket_family == AF_INET6) { + inet_ntop(AF_INET6, &(client->addr6.sin6_addr), str_client, sizeof(str_client)); + twamp_log(SINFO, "Server received RequestTWSession message"); + } else { + char str_server[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(client->addr.sin_addr), str_client, INET_ADDRSTRLEN); + struct in_addr se_addr; + se_addr.s_addr = req->ReceiverAddress; + inet_ntop(AF_INET, &(se_addr), str_server, INET_ADDRSTRLEN); + twamp_log(SINFO, "Server %s received RequestTWSession message with port %d", str_server, ntohs(req->ReceiverPort)); + } + /* Check port test packets if its allowed by PortAllowedList parameter */ + if(cur_twamp_conf.port_list[0] != '\0') { + if(!check_port_allowed(ntohs(req->ReceiverPort))) { + twamp_log(SINFO, "Port %d is not allowed", ntohs(req->ReceiverPort)); + return -1; + } + } + + int rv = send_accept_session(client, req); + if (rv <= 0) { + twamp_log(SCRIT,"Failed to send the Accept-Session message"); + } + return rv; +} + +/* This function will receive a TWAMP-Test packet and will send a response. In TWAMP the Session-Sender (in our case the Control-Client, meaning the + * TWAMP-Client) is always sending TWAMP-Test packets and the Session-Reflector (Server) is receiving TWAMP-Test packets. + */ +static int receive_test_message(struct client_info *client, int session_index) +{ + struct sockaddr_in addr; + struct sockaddr_in6 addr6; + socklen_t len = sizeof(addr); + char str_client[INET6_ADDRSTRLEN]; + + inet_ntop(socket_family, (socket_family == AF_INET6)? (void*) &(client->addr6.sin6_addr) : (void*) &(client->addr.sin_addr), str_client, sizeof(str_client)); + + ReflectorUPacket pack_reflect; + memset(&pack_reflect, 0, sizeof(pack_reflect)); + + SenderUPacket pack; + memset(&pack, 0, sizeof(pack)); + + /* New for recvmsg */ + struct msghdr *message = malloc(sizeof(struct msghdr)); + struct cmsghdr *c_msg; + char *control_buffer = malloc(TST_PKT_SIZE); + uint16_t control_length = TST_PKT_SIZE; + + memset(message, 0, sizeof(*message)); + message->msg_name = (socket_family == AF_INET6)? (void*)&addr6: (void*)&addr; + message->msg_namelen = len; + message->msg_iov = malloc(sizeof(struct iovec)); + message->msg_iov->iov_base = &pack; + message->msg_iov->iov_len = TST_PKT_SIZE; + message->msg_iovlen = 1; + message->msg_control = control_buffer; + message->msg_controllen = control_length; + + int rv = recvmsg(client->sessions[session_index].socket, message, 0); + pack_reflect.receive_time = get_timestamp(); + + char str_server[INET6_ADDRSTRLEN]; /* String for Client IP address */ + + inet_ntop(socket_family, (socket_family == AF_INET6)? (void*) &(addr6.sin6_addr) : (void*) &(addr.sin_addr), str_server, sizeof(str_server)); + if (rv <= 0) { + twamp_log(SCRIT,"Failed to receive TWAMP-Test packet"); + return rv; + } else if (rv < 14) { + twamp_log(SCRIT,"Short TWAMP-Test packet"); + return rv; + } + + /* Get TTL/TOS values from IP header */ + uint8_t fw_ttl = 0; + uint8_t fw_tos = 0; + + for (c_msg = CMSG_FIRSTHDR(message); c_msg; c_msg = (CMSG_NXTHDR(message, c_msg))) { + if ((c_msg->cmsg_level == IPPROTO_IP && c_msg->cmsg_type == IP_TTL) || (c_msg->cmsg_level == IPPROTO_IPV6 && c_msg->cmsg_type == IPV6_HOPLIMIT)) { + fw_ttl = *(int *)CMSG_DATA(c_msg); + } else if (c_msg->cmsg_level == IPPROTO_IP && c_msg->cmsg_type == IP_TOS) { + fw_tos = *(int *)CMSG_DATA(c_msg); + } else { + twamp_log(SINFO, "Warning, unexpected data of level %i and type %i", c_msg->cmsg_level, c_msg->cmsg_type); + } + } + + twamp_log(SINFO, "Received TWAMP-Test message from %s", inet_ntoa(addr.sin_addr)); + pack_reflect.seq_number = htonl(client->sessions[session_index].seq_nb++); + pack_reflect.error_estimate = htons(0x8001); // Sync = 1, Multiplier = 1 + pack_reflect.sender_seq_number = pack.seq_number; + pack_reflect.sender_time = pack.time; + pack_reflect.sender_error_estimate = pack.error_estimate; + pack_reflect.sender_ttl = fw_ttl; // Copy from the IP header packet from Sender + if ((client->mode & kModeDSCPECN) == kModeDSCPECN) { + pack_reflect.sender_tos = fw_tos; // Copy from the IP header packet from Sender + } + + if(socket_family == AF_INET6) { + addr.sin_port = client->sessions[session_index].req.SenderPort; + } else { + addr6.sin6_port = client->sessions[session_index].req.SenderPort; + } + /* FW Loss Calculation */ + + if (client->sessions[session_index].fw_msg == 0) { + client->sessions[session_index].fw_msg = 1; + /* Response packet for TOS with ECN */ + if ((fw_tos & 0x03) > 0) { + uint8_t ecn_tos = (fw_tos & 0x03) - (((fw_tos & 0x2) >> 1) & (fw_tos & 0x1)); + set_socket_tos(client->sessions[session_index].socket, (client->sessions[session_index].req.TypePDescriptor << 2) + ecn_tos); + } + } else { + client->sessions[session_index].fw_msg = client->sessions[session_index].fw_msg + ntohl(pack.seq_number) - client->sessions[session_index].snd_nb; + client->sessions[session_index].fw_lst_msg = client->sessions[session_index].fw_lst_msg + ntohl(pack.seq_number) - client->sessions[session_index].snd_nb - 1; + } + client->sessions[session_index].snd_nb = ntohl(pack.seq_number); + + /* Response packet */ + pack_reflect.time = get_timestamp(); + + if(socket_family == AF_INET6) { + if (rv < 41) { + rv = sendto(client->sessions[session_index].socket, &pack_reflect, 41, 0, (struct sockaddr *)&addr6, sizeof(addr6)); + } else { + rv = sendto(client->sessions[session_index].socket, &pack_reflect, rv, 0, (struct sockaddr *)&addr6, sizeof(addr6)); + } + } else { + if (rv < 41) { + rv = sendto(client->sessions[session_index].socket, &pack_reflect, 41, 0, (struct sockaddr *)&addr, sizeof(addr)); + } else { + rv = sendto(client->sessions[session_index].socket, &pack_reflect, rv, 0, (struct sockaddr *)&addr, sizeof(addr)); + } + } + + if (rv <= 0) { + twamp_log(SCRIT,"Failed to send TWAMP-Test packet"); + } + + /* Print the FW metrics */ + print_metrics_server(str_client, socket_family == AF_INET6 ? ntohs(addr6.sin6_port): ntohs(addr.sin_port), ntohs(client->sessions[session_index].req.ReceiverPort), (client->sessions[session_index].req.TypePDescriptor << 2), fw_tos, &pack_reflect); + + if ((client->sessions[session_index].fw_msg % 10) == 0) { + twamp_log(SINFO,"FW Lost packets: %u/%u", client->sessions[session_index].fw_lst_msg, client->sessions[session_index].fw_msg); + twamp_log(SINFO,"FW Loss Ratio: %3.2f%%", (float)100 * client->sessions[session_index].fw_lst_msg / client->sessions[session_index].fw_msg); + //printf("FW Lost packets: %u/%u, FW Loss Ratio: %3.2f%%\n", client->sessions[session_index].fw_lst_msg, client->sessions[session_index].fw_msg, (float)100 * client->sessions[session_index].fw_lst_msg / client->sessions[session_index].fw_msg); + } + return rv; +} + +int twamp_connect(void) +{ + int listenfd, newsockfd; + struct client_info clients[MAX_CLIENTS]; + struct sockaddr_in client_addr; + struct sockaddr_in6 client_addr6; + int rv; + + /* Obtain start server time in TWAMP format */ + TWAMPTimestamp StartTime = get_timestamp(); + + if(cur_twamp_conf.ip_version == 4) + socket_family = AF_INET; + else + socket_family = AF_INET6; + + listenfd = socket(socket_family, SOCK_STREAM, 0); + if (listenfd < 0) { + twamp_log(SCRIT,"Error opening socket"); + return -1; + } + + int ret = setsockopt(listenfd, SOL_SOCKET, SO_BINDTODEVICE, cur_twamp_conf.device, strlen(cur_twamp_conf.device)+1); + if(ret) { + twamp_log(SCRIT,"Error on setsockopt with ret %d", ret); + return -1; + } + + if(socket_family == AF_INET6) { + /* Set Server address and bind on the TWAMP port */ + struct sockaddr_in6 serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin6_family = AF_INET6; + serv_addr.sin6_addr = in6addr_any; + serv_addr.sin6_port = htons(cur_twamp_conf.port); + + if (bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + twamp_log(SCRIT,"Error on binding"); + return -1; + } + } else { + /* Set Server address and bind on the TWAMP port */ + struct sockaddr_in serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(cur_twamp_conf.port); + + if (bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) < 0) { + twamp_log(SCRIT,"Error on binding"); + return -1; + } + } + + used_sockets++; + + /* Start listening on the TWAMP port for new TWAMP-Control connections */ + if (listen(listenfd, MAX_CLIENTS)) { + twamp_log(SCRIT,"Error on listen"); + return -1; + } + + FD_ZERO(&read_fds); + FD_SET(listenfd, &read_fds); + fd_max = listenfd; + + memset(clients, 0, MAX_CLIENTS * sizeof(struct client_info)); + fd_set tmp_fds; + FD_ZERO(&tmp_fds); + + while (1) { + tmp_fds = read_fds; + if (select(fd_max + 1, &tmp_fds, NULL, NULL, NULL) < 0) { + twamp_log(SCRIT,"Error in select"); + close(listenfd); + return -1; + } + + /* If an event happened on the listenfd, then a new TWAMP-Control connection is received */ + if (FD_ISSET(listenfd, &tmp_fds)) { + uint32_t client_len = (socket_family == AF_INET6)? sizeof(client_addr6) : sizeof(client_addr); + if ((newsockfd = accept(listenfd, (socket_family == AF_INET6) ? (struct sockaddr *)&client_addr6 : (struct sockaddr *)&client_addr, &client_len)) < 0) { + twamp_log(SCRIT,"Error in accept"); + } else { + /* Add a new client if there are any slots available */ + int pos = find_empty_client(clients, MAX_CLIENTS); + uint16_t mode_mask = 0; + if (pos != -1) { + clients[pos].status = kConnected; + clients[pos].socket = newsockfd; + clients[pos].addr = client_addr; + clients[pos].addr6 = client_addr6; + clients[pos].mode = authmode; + clients[pos].sess_no = 0; + used_sockets++; + FD_SET(newsockfd, &read_fds); + if (newsockfd > fd_max) + fd_max = newsockfd; + mode_mask = 0x01FF; + } + + char str_client[INET6_ADDRSTRLEN]; /* String for Client IP address */ + inet_ntop(socket_family, (socket_family == AF_INET6) ? (void*) &(clients[pos].addr6.sin6_addr) : (void*) &(clients[pos].addr.sin_addr), str_client, sizeof(str_client)); + twamp_log(SINFO,"Receive a TCP connection from %s", str_client); + /* Check ip test packets if its allowed by IPAllowedList parameter */ + if(cur_twamp_conf.ip_list[0] != '\0') { + if(!check_ip_address_allowed(str_client)) { + twamp_log(SINFO, "IP Address %d is not allowed", str_client); + close(listenfd); + return -1; + } + } + rv = send_greeting(mode_mask, &clients[pos]); + } + } + + /* Receives other packets from the established TWAMP-Control sessions */ + uint8_t buffer[4096]; + int i, j; + for (i = 0; i < MAX_CLIENTS; i++) + /* It can only receive TWAMP-Control messages from Online clients */ + if (clients[i].status != kOffline) + if (FD_ISSET(clients[i].socket, &tmp_fds)) { + switch (clients[i].status) { + case kConnected: + /* If a TCP session has been established and a ServerGreeting has been sent, wait for the SetUpResponse and finish the TWAMP-Control setup */ + rv = receive_greet_response(&clients[i]); + if (rv > 32) { + rv = send_start_serv(&clients[i], StartTime); + } else { + rv = send_start_serv(&clients[i], ZeroT); + } + break; + case kConfigured: + /* Reset the buffer to receive a new message */ + memset(buffer, 0, 4096); + rv = recv(clients[i].socket, buffer, 4096, 0); + if (rv <= 0) { + cleanup_client(&clients[i]); + break; + } + /* Check the message received: It can only be StartSessions or RequestTWSession */ + switch (buffer[0]) { + case kStartSessions: + rv = receive_start_sessions(&clients[i]); + break; + case kRequestTWSession: + rv = receive_request_session(&clients[i], (RequestSession *) buffer); + break; + default: + break; + } + + if (rv <= 0) + cleanup_client(&clients[i]); + break; + case kTesting: + /* In this state can only receive a StopSessions msg */ + memset(buffer, 0, 4096); + rv = recv(clients[i].socket, buffer, 4096, 0); + if (rv <= 0) { + cleanup_client(&clients[i]); + break; + } + if (buffer[0] == kStopSessions) { + rv = receive_stop_sessions(&clients[i]); + } + break; + default: + break; + } + } + + /* Check for TWAMP-Test packets */ + for (i = 0; i < MAX_CLIENTS; i++) { + struct timeval current; + gettimeofday(¤t, NULL); + + if (clients[i].status == kTesting) { + uint8_t has_active_test_sessions = 0; + for (j = 0; j < clients[i].sess_no; j++) { + rv = get_actual_shutdown(¤t, &clients[i].shutdown_time, &clients[i].sessions[j].req.Timeout); + if (rv > 0) { + has_active_test_sessions = 1; + if (FD_ISSET(clients[i].sessions[j].socket, &tmp_fds)) { + rv = receive_test_message(&clients[i], j); + } + } else { + FD_CLR(clients[i].sessions[j].socket, &read_fds); + close(clients[i].sessions[j].socket); + used_sockets--; + clients[i].sessions[j].socket = -1; + + /* print loss result */ + twamp_log(SINFO, "Session: %u, FW Lost packets: %u/%u, FW Loss Ratio: %3.2f%%", j, clients[i].sessions[j].fw_lst_msg, clients[i].sessions[j].fw_msg, (float)100 * clients[i].sessions[j].fw_lst_msg / clients[i].sessions[j].fw_msg); + + } + } + if (!has_active_test_sessions) { + memset(&clients[i].shutdown_time, 0, sizeof(clients[i].shutdown_time)); + clients[i].sess_no = 0; + clients[i].status = kConfigured; + } + } + } + } + return 0; +} + +char *get_twamp_refector_option(char *instance, char *option) +{ + struct uci_section *s; + char *v, *twamp_id, *curr_interface; + dmuci_foreach_section("cwmp_twamp", "twamp_refector", s) { + twamp_id = dmuci_get_value_bysection(s, "id"); + if(strcmp(twamp_id, instance) == 0) + { + v = dmuci_get_value_bysection(s, option); + return v; + } + } + v = ""; + return v; +} + +int twamp_init(void) +{ + char *id, *interface, *value = NULL; + int a; + + value = dmuci_get_value("cwmp_twamp", "twamp", "log_level"); + if(value != NULL && *value != '\0') { + a = atoi(value); + cur_twamp_conf.loglevel = a; + } + else + cur_twamp_conf.loglevel = DEFAULT_LOGLEVEL; + twamp_log(SDEBUG,"TWAMP Reflector Log Level:%d", cur_twamp_conf.loglevel); + + id = dmuci_get_value("cwmp_twamp", "twamp", "id"); + cur_twamp_conf.enable = atoi(get_twamp_refector_option(id, "enable")); + cur_twamp_conf.interface = strdup(get_twamp_refector_option(id, "interface")); + cur_twamp_conf.device = strdup(get_twamp_refector_option(id, "device")); + cur_twamp_conf.ip_version = atoi(get_twamp_refector_option(id, "ip_version")); + cur_twamp_conf.port = atoi(get_twamp_refector_option(id, "port")); + cur_twamp_conf.max_ttl = atoi(get_twamp_refector_option(id, "max_ttl")); + cur_twamp_conf.ip_list = strdup(get_twamp_refector_option(id, "ip_list")); + cur_twamp_conf.port_list = strdup(get_twamp_refector_option(id, "port_list")); + + twamp_log(SDEBUG,"TWAMP Reflector Enable: %d", cur_twamp_conf.enable); + twamp_log(SDEBUG,"TWAMP Reflector Interface: %s", cur_twamp_conf.interface); + twamp_log(SDEBUG,"TWAMP Reflector Device: %s", cur_twamp_conf.device); + twamp_log(SDEBUG,"TWAMP Reflector Port: %d", cur_twamp_conf.port); + twamp_log(SDEBUG,"TWAMP Reflector MaximumTTL: %d", cur_twamp_conf.max_ttl); + twamp_log(SDEBUG,"TWAMP Reflector IPAllowedList: %s", cur_twamp_conf.ip_list); + twamp_log(SDEBUG,"TWAMP Reflector PortAllowedList: %s", cur_twamp_conf.port_list); + + return 0; +} + +void twamp_exit(void) +{ + free(cur_twamp_conf.interface); + free(cur_twamp_conf.device); + free(cur_twamp_conf.ip_list); + free(cur_twamp_conf.port_list); +} + +int main(int argc, char *argv[]) +{ + dmuci_init(); + twamp_init(); + dmuci_fini(); + twamp_log(SINFO,"START TWAMP Reflector"); + + twamp_connect(); + + twamp_exit(); + twamp_log(SINFO,"EXIT TWAMP Reflector"); + return 0; +} diff --git a/twamp/twamp.h b/twamp/twamp.h new file mode 100644 index 0000000..7f6890c --- /dev/null +++ b/twamp/twamp.h @@ -0,0 +1,237 @@ +/* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Copyright (C) 2019 iopsys Software Solutions AB +* Author: Amin Ben Ramdhane +* +* Name: Emma Mirică +* Project: TWAMP Protocol +* Class: OSS +* Email: emma.mirica@cti.pub.ro +* Contributions: stephanDB +* +*/ + +/* + * The following logical-model will be implemented: + * + * +----------------+ +-------------------+ + * | Control-Client |<--TWAMP-Control-->| Server | + * | | | | + * | Session-Sender |<--TWAMP-Test----->| Session-Reflector | + * +----------------+ +-------------------+ + * + */ + +#ifndef _TWAMP_H__ +#define _TWAMP_H__ + +#include +#include +#include +#include + +#define CHECK_TIMES 100 +#define LOSTTIME 2 /* SECONDS - Timeout for TWAMP test packet */ +#define MAX_CLIENTS 10 +#define MAX_SESSIONS_PER_CLIENT 10 + +enum CommandNumber { + kReserved, + kForbidden, + kStartSessions, + kStopSessions, + kReserved4, + kRequestTWSession, + kExperimentation +}; + +enum Mode { + kModeReserved = 0, + kModeUnauthenticated = 1, + kModeAuthenticated = 2, + kModeEncrypted = 4, + kModeHybrid = 8, /* Unauthenticated test, encrypted control */ + kModeIndividual = 16, + kModeReflectOctets = 32, + KModeSymmetrical = 64, + KModeIKEv2Derived = 128, + kModeDSCPECN = 256 +}; + +enum AcceptCode { + kOK, + kFailure, + kInternalError, + kAspectNotSupported, + kPermanentResourceLimitation, + kTemporaryResourceLimitation +}; + +typedef enum { + kOffline = 0, + kConnected, + kConfigured, + kTesting +} ClientStatus; + +typedef struct twamp_timestamp { + uint32_t integer; + uint32_t fractional; +} TWAMPTimestamp; + +/*****************************************/ +/* */ +/* TWAMP-Control specific messages */ +/* */ +/*****************************************/ + +/* First messsage sent by the Server to the Control-Client to establish a connection */ +typedef struct server_greeting { + uint8_t Unused[12]; + /* Modes = bit-wise OR between Mode values + * First 23 bits MUST be zero in TWAMP (29 in first version)*/ + uint32_t Modes; + uint8_t Challenge[16]; /* Random sequence of bytes generated by the server */ + uint8_t Salt[16]; + uint32_t Count; /* MUST be a power of 2. Minimum 1024 */ + uint8_t MBZ[12]; +} ServerGreeting; + +/* The Control-Client's response to the Server's greeting */ +typedef struct control_client_greeting_response { + uint32_t Mode; /* if 0 -> the Server does not wish to communicate */ + uint8_t KeyID[80]; + uint8_t Token[64]; + uint8_t ClientIV[16]; +} SetUpResponse; + +/* The Server sends a start message to conclude the TWAMP-Control session */ +typedef struct server_start { + uint8_t MBZ1[15]; + uint8_t Accept; /* 0 means Continue. See 3.3 of RFC 4656 */ + uint8_t ServerIV[16]; + TWAMPTimestamp StartTime; /* TWAMPTimestamp; 0 if Accept is NonZero. */ + uint8_t MBZ2[8]; +} ServerStart; + +/* The Control-Client sends a RequestSession packet for each TWAMP-Test session */ +typedef struct request_session { + uint8_t Type; /* 5 / CommandNumber */ + uint8_t IPVN; /* MBZ | IPVN */ + uint8_t ConfSender; /* 0 */ + uint8_t ConfReceiver; /* 0 */ + uint32_t SlotsNo; /* 0 */ + uint32_t PacketsNo; /* 0 */ + uint16_t SenderPort; + uint16_t ReceiverPort; + uint32_t SenderAddress; + uint8_t MBZ1[12]; /* Sender Address Cont */ + uint32_t ReceiverAddress; + uint8_t MBZ2[12]; /* Receiver Address Cont */ + uint8_t SID[16]; /* 0 */ + uint32_t PaddingLength; + TWAMPTimestamp StartTime; + TWAMPTimestamp Timeout; + uint32_t TypePDescriptor; + uint16_t OctetsToBeReflected; + uint16_t PadLenghtToReflect; + uint8_t MBZ3[4]; + uint8_t HMAC[16]; +} RequestSession; + +/* The Server's response to the RequestSession packet */ +typedef struct accept_session_packet { + uint8_t Accept; /* 3 if not supported */ + uint8_t MBZ1; + uint16_t Port; + uint8_t SID[16]; /* Generated by server */ + //uint16_t ReflectedOctets; + //uint16_t ServerOctets; + uint8_t MBZ2[8]; + uint8_t HMAC[16]; +} AcceptSession; + +/* The Control-Client sends a StartSessions message to start all accepted TWAMP-Test sessions */ +typedef struct start_message1 { + uint8_t Type; /* 2 */ + uint8_t MBZ[15]; + uint8_t HMAC[16]; +} StartSessions; + +/* When it receives a StartSessions, the Server responds with a StartACK */ +typedef struct start_ack { + uint8_t Accept; + uint8_t MBZ[15]; + uint8_t HMAC[16]; +} StartACK; + +/* The Control-Client sends a StopSessions message to stop all active TWAMP-Test sessions */ +typedef struct twamp_stop { + uint8_t Type; /* 3 */ + uint8_t Accept; + uint8_t MBZ1[2]; + uint32_t SessionsNo; + uint8_t MBZ2[8]; + uint8_t HMAC[16]; +} StopSessions; + +/*****************************************/ +/* */ +/* TWAMP-Test specific messages */ +/* */ +/*****************************************/ +#define TST_PKT_SIZE 1472 //1472 (MTU 1514) + +/* Session-Sender TWAMP-Test packet for Unauthenticated mode */ +typedef struct test_packet { + uint32_t seq_number; + TWAMPTimestamp time; + uint16_t error_estimate; + uint8_t padding[TST_PKT_SIZE - 14]; +} SenderUPacket; + +/* Session-Reflector TWAMP-Test packet for Unauthenticated mode */ +typedef struct reflector_unauth_packet { + uint32_t seq_number; + TWAMPTimestamp time; + uint16_t error_estimate; + uint8_t mbz1[2]; + TWAMPTimestamp receive_time; + uint32_t sender_seq_number; + TWAMPTimestamp sender_time; + uint16_t sender_error_estimate; + uint8_t mbz2[2]; + uint8_t sender_ttl; + uint8_t sender_tos; + uint8_t padding[TST_PKT_SIZE - 42]; +} ReflectorUPacket; + +struct twamp_config +{ + bool enable; + char *interface; + char *device; + int ip_version; + int port; + int max_ttl; + char *ip_list; + char *port_list; + int loglevel; +}; + +extern struct twamp_config cur_twamp_conf; + +void timeval_to_timestamp(const struct timeval *tv, TWAMPTimestamp * ts); +void timestamp_to_timeval(const TWAMPTimestamp * ts, struct timeval *tv); +uint64_t get_usec(const TWAMPTimestamp * ts); +TWAMPTimestamp get_timestamp(); +int get_actual_shutdown(const struct timeval *tv, const struct timeval *ts, const TWAMPTimestamp * t); +void print_metrics_server(char *addr_cl, uint16_t snd_port, uint16_t rcv_port, uint8_t snd_tos, uint8_t fw_tos, const ReflectorUPacket * pack); +void set_socket_option(int socket, uint8_t ip_ttl); +void set_socket_tos(int socket, uint8_t ip_tos); + +#endif /* _TWAMP_H__ */ diff --git a/twamp/twamplog.c b/twamp/twamplog.c new file mode 100644 index 0000000..a5d7f6d --- /dev/null +++ b/twamp/twamplog.c @@ -0,0 +1,55 @@ +/* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Copyright (C) 2019 iopsys Software Solutions AB +* Author: Amin Ben Ramdhane +*/ + +#include +#include +#include +#include "twamplog.h" +#include "twamp.h" +#define DEBUG + +static const int log_syslogmap[] = { + [SCRIT] = LOG_CRIT, + [SWARNING] = LOG_WARNING, + [SNOTICE] = LOG_NOTICE, + [SINFO] = LOG_INFO, + [SDEBUG] = LOG_DEBUG +}; + +static const char* log_str[] = { + [SCRIT] = "CRITICAL", + [SWARNING] = "WARNING", + [SNOTICE] = "NOTICE", + [SINFO] = "INFO", + [SDEBUG] = "DEBUG" +}; + +void twamp_log(int priority, const char *format, ...) +{ + va_list vl; + char *log; + + if (priority <= cur_twamp_conf.loglevel) { +#ifdef DEBUG + time_t t = time(NULL); + struct tm tm = *localtime(&t); + va_start(vl, format); + printf("%d-%02d-%02d %02d:%02d:%02d [twamp] %s - ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, log_str[priority]); + vprintf(format, vl); + va_end(vl); + printf("\n"); +#endif + openlog("twamp", 0, LOG_DAEMON); + va_start(vl, format); + vsyslog(log_syslogmap[priority], format, vl); + va_end(vl); + closelog(); + } +} diff --git a/twamp/twamplog.h b/twamp/twamplog.h new file mode 100644 index 0000000..239548b --- /dev/null +++ b/twamp/twamplog.h @@ -0,0 +1,27 @@ +/* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Copyright (C) 2019 iopsys Software Solutions AB +* Author: Amin Ben Ramdhane +*/ + +#ifndef _TWAMPLOG_H_ +#define _TWAMPLOG_H_ + +#define DEFAULT_LOGLEVEL SINFO + +enum udpechoserver_log_level_enum { + SCRIT, + SWARNING, + SNOTICE, + SINFO, + SDEBUG, + __MAX_SLOG +}; + +void twamp_log(int priority, const char *format, ...); + +#endif /* _TWAMPLOG_H_ */ diff --git a/twamp/twamptimestamp.c b/twamp/twamptimestamp.c new file mode 100644 index 0000000..ceb058a --- /dev/null +++ b/twamp/twamptimestamp.c @@ -0,0 +1,195 @@ +/* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Copyright (C) 2019 iopsys Software Solutions AB +* Author: Amin Ben Ramdhane +* +* Name: Emma Mirică +* Project: TWAMP Protocol +* Class: OSS +* Email: emma.mirica@cti.pub.ro +* Contributions: stephanDB +* +*/ + +#include +#include +#include +#include +#include +#include "twamp.h" +#include "twamplog.h" + +void timeval_to_timestamp(const struct timeval *tv, TWAMPTimestamp * ts) +{ + if (!tv || !ts) + return; + + /* Unix time to NTP */ + ts->integer = tv->tv_sec + 2208988800uL; + ts->fractional = (uint32_t) ((double)tv->tv_usec * ((double)(1uLL << 32) + / (double)1e6)); + + ts->integer = htonl(ts->integer); + ts->fractional = htonl(ts->fractional); +} + +void timestamp_to_timeval(const TWAMPTimestamp * ts, struct timeval *tv) +{ + if (!tv || !ts) + return; + + TWAMPTimestamp ts_host_ord; + + ts_host_ord.integer = ntohl(ts->integer); + ts_host_ord.fractional = ntohl(ts->fractional); + + /* NTP to Unix time */ + tv->tv_sec = ts_host_ord.integer - 2208988800uL; + tv->tv_usec = (uint32_t) (double)ts_host_ord.fractional * (double)1e6 / (double)(1uLL << 32); +} + +TWAMPTimestamp get_timestamp() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + TWAMPTimestamp ts; + timeval_to_timestamp(&tv, &ts); + return ts; +} + +uint64_t get_usec(const TWAMPTimestamp * ts) +{ + struct timeval tv; + timestamp_to_timeval(ts, &tv); + + return tv.tv_sec * 1000000 + tv.tv_usec; +} + +int get_actual_shutdown(const struct timeval *tv, const struct timeval *ts, + const TWAMPTimestamp * t) +{ + /* If ts is 0 then no StopSessions message was received */ + if ((ts->tv_sec * 1000000 + ts->tv_usec) == 0) + return 1; + /* Else compute time difference */ + uint64_t current = tv->tv_sec * 1000000 + tv->tv_usec; + uint64_t shutdown = ts->tv_sec * 1000000 + ts->tv_usec; + uint64_t timeout = get_usec(t); + + /* This should be ok, as no difference is computed */ + if (current > shutdown + timeout) + return 1; + return 0; +} + +void print_metrics_server(char *addr_cl, uint16_t snd_port, uint16_t rcv_port, + uint8_t snd_tos, uint8_t fw_tos, + const ReflectorUPacket * pack) +{ + + /* Compute timestamps in usec */ + uint64_t t_sender_usec1 = get_usec(&pack->sender_time); + uint64_t t_receive_usec1 = get_usec(&pack->receive_time); + uint64_t t_reflsender_usec1 = get_usec(&pack->time); + + /* Compute delays */ + int64_t fwd1 = t_receive_usec1 - t_sender_usec1; + int64_t intd1 = t_reflsender_usec1 - t_receive_usec1; + char sync1 = 'Y'; + if (fwd1 < 0) { + sync1 = 'N'; + } + + /* Sequence number */ + uint32_t snd_nb = ntohl(pack->sender_seq_number); + uint32_t rcv_nb = ntohl(pack->seq_number); + + /* Sender TOS with ECN from FW TOS */ + snd_tos = snd_tos + (fw_tos & 0x3) - (((fw_tos & 0x2) >> 1) & (fw_tos & 0x1)); + + /* Print different metrics */ + twamp_log(SINFO,"Snd@: %s", addr_cl); + twamp_log(SINFO,"Time: %.0f", (double)t_sender_usec1 * 1e-3); + twamp_log(SINFO,"Snd#: %d", snd_nb); + twamp_log(SINFO,"Rcv#: %d", rcv_nb); + twamp_log(SINFO,"SndPt: %d", snd_port); + twamp_log(SINFO,"RcvPt: %d", rcv_port); + twamp_log(SINFO,"Sync: %c", sync1); + twamp_log(SINFO,"TTL: %d", pack->sender_ttl); + twamp_log(SINFO,"SndTOS: %d", snd_tos); + twamp_log(SINFO,"FW_TOS: %d", fw_tos); + twamp_log(SINFO,"Int D: %.3f", (double)intd1 * 1e-3); +} + +void set_socket_option(int socket, uint8_t ip_ttl) +{ + /* Set socket options : timeout, IPTTL, IP_RECVTTL, IP_RECVTOS */ + uint8_t One = 1; + int result; + + /* Set Timeout */ + struct timeval timeout = { LOSTTIME, 0 }; //set timeout for 2 seconds + + /* Set receive UDP message timeout value */ +#ifdef SO_RCVTIMEO + result = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, + (char *)&timeout, sizeof(struct timeval)); + if (result != 0) { + twamp_log(SDEBUG, "[PROBLEM] Cannot set the timeout value for reception.\n"); + } +#else + twamp_log(SDEBUG, "No way to set the timeout value for incoming packets on that platform.\n"); +#endif + + /* Set IPTTL value to twamp standard: 255 */ +#ifdef IP_TTL + result = setsockopt(socket, IPPROTO_IP, IP_TTL, &ip_ttl, sizeof(ip_ttl)); + if (result != 0) { + twamp_log(SDEBUG, "[PROBLEM] Cannot set the TTL value for emission.\n"); + } +#else + twamp_log(SDEBUG, "No way to set the TTL value for leaving packets on that platform.\n"); +#endif + + /* Set receive IP_TTL option */ +#ifdef IP_RECVTTL + result = setsockopt(socket, IPPROTO_IP, IP_RECVTTL, &One, sizeof(One)); + if (result != 0) { + twamp_log(SDEBUG, "[PROBLEM] Cannot set the socket option for TTL reception.\n"); + } +#else + twamp_log(SDEBUG, "No way to ask for the TTL of incoming packets on that platform.\n"); +#endif + + /* Set receive IP_TOS option */ +#ifdef IP_RECVTOS + result = setsockopt(socket, IPPROTO_IP, IP_RECVTOS, &One, sizeof(One)); + if (result != 0) { + twamp_log(SDEBUG, "[PROBLEM] Cannot set the socket option for TOS reception.\n"); + } +#else + twamp_log(SDEBUG, "No way to ask for the TOS of incoming packets on that platform.\n"); +#endif + +} + +void set_socket_tos(int socket, uint8_t ip_tos) +{ + /* Set socket options : IP_TOS */ + int result; + + /* Set IP TOS value */ +#ifdef IP_TOS + result = setsockopt(socket, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos)); + if (result != 0) { + twamp_log(SDEBUG, "[PROBLEM] Cannot set the TOS value for emission.\n"); + } +#else + twamp_log(SDEBUG, "No way to set the TOS value for leaving packets on that platform.\n"); +#endif + +} diff --git a/twamp/twampuci.c b/twamp/twampuci.c new file mode 100644 index 0000000..3b39d25 --- /dev/null +++ b/twamp/twampuci.c @@ -0,0 +1,270 @@ +/* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Copyright (C) 2019 iopsys Software Solutions AB +* Author: Amin Ben Ramdhane +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "twampuci.h" + +struct uci_context *uci_ctx; + +int dmuci_init(void) +{ + uci_ctx = uci_alloc_context(); + if (!uci_ctx) { + return -1; + } + return 0; +} + +int dmuci_fini(void) +{ + if (uci_ctx) { + uci_free_context(uci_ctx); + } + + return 0; +} + +static bool dmuci_validate_section(const char *str) +{ + if (!*str) + return false; + + for (; *str; str++) { + unsigned char c = *str; + + if (isalnum(c) || c == '_') + continue; + + return false; + } + return true; +} + +static int dmuci_init_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *package, char *section, char *option, char *value) +{ + char *last = NULL; + char *tmp; + + memset(ptr, 0, sizeof(struct uci_ptr)); + + /* value */ + if (value) { + ptr->value = value; + } + ptr->package = package; + if (!ptr->package) + goto error; + + ptr->section = section; + if (!ptr->section) { + ptr->target = UCI_TYPE_PACKAGE; + goto lastval; + } + + ptr->option = option; + if (!ptr->option) { + ptr->target = UCI_TYPE_SECTION; + goto lastval; + } else { + ptr->target = UCI_TYPE_OPTION; + } + +lastval: + if (ptr->section && !dmuci_validate_section(ptr->section)) + ptr->flags |= UCI_LOOKUP_EXTENDED; + + return 0; + +error: + return -1; +} + +struct uci_section *dmuci_walk_section(char *package, char *section_type, struct uci_section *prev_section) +{ + struct uci_ptr ptr; + struct uci_element *e; + struct uci_section *next_section; + + if (section_type == NULL) { + if (prev_section) { + e = &prev_section->e; + if (e->list.next == &prev_section->package->sections) + return NULL; + e = container_of(e->list.next, struct uci_element, list); + next_section = uci_to_section(e); + return next_section; + } + else { + if (dmuci_init_ptr(uci_ctx, &ptr, package, NULL, NULL, NULL)) { + return NULL; + } + if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK) { + return NULL; + } + if (ptr.p->sections.next == &ptr.p->sections) + return NULL; + e = container_of(ptr.p->sections.next, struct uci_element, list); + next_section = uci_to_section(e); + + return next_section; + } + } + else { + struct uci_list *ul, *u = NULL; + struct uci_list *shead = NULL; + + if (prev_section) { + ul = &prev_section->e.list; + shead = &prev_section->package->sections; + } + else { + if (dmuci_init_ptr(uci_ctx, &ptr, package, NULL, NULL, NULL)) { + return NULL; + } + if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK) { + return NULL; + } + ul = &ptr.p->sections; + shead = &ptr.p->sections; + } + while (ul->next != shead) { + e = container_of(ul->next, struct uci_element, list); + next_section = uci_to_section(e); + if (strcmp(next_section->type, section_type) == 0) + return next_section; + ul = ul->next; + } + return NULL; + } + return NULL; +} + +void dmuci_print_list(struct uci_list *uh, char **val, char *delimiter) +{ + struct uci_element *e; + static char buffer[512]; + int dlen = strlen(delimiter); + int olen = 0; + char *buf = buffer; + *buf = '\0'; + + uci_foreach_element(uh, e) { + if (*buf) { + strcat(buf, delimiter); + strcat(buf, e->name); + } + else { + strcpy(buf, e->name); + } + } + *val = buf; +} + +struct uci_element *dmuci_lookup_list(struct uci_list *list, const char *name) +{ + struct uci_element *e; + + uci_foreach_element(list, e) { + if (!strcmp(e->name, name)) + return e; + } + return NULL; +} + +int uci_lookup_ptr_bysection(struct uci_context *ctx, struct uci_ptr *ptr, struct uci_section *section, char *option, char *value) +{ + struct uci_element *e; + memset(ptr, 0, sizeof(struct uci_ptr)); + + ptr->package = section->package->e.name; + ptr->section = section->e.name; + ptr->option = option; + ptr->value = value; + ptr->flags |= UCI_LOOKUP_DONE; + + ptr->p = section->package; + ptr->s = section; + + if (ptr->option) { + e = dmuci_lookup_list(&ptr->s->options, ptr->option); + if (!e) + return UCI_OK; + ptr->o = uci_to_option(e); + ptr->last = e; + ptr->target = UCI_TYPE_OPTION; + } + else { + ptr->last = &ptr->s->e; + ptr->target = UCI_TYPE_SECTION; + } + + ptr->flags |= UCI_LOOKUP_COMPLETE; + + return UCI_OK; +} + +char *dmuci_get_value_bysection(struct uci_section *section, char *option) +{ + struct uci_ptr ptr; + char *val = ""; + + if (uci_lookup_ptr_bysection(uci_ctx, &ptr, section, option, NULL) != UCI_OK) { + return val; + } + + if (!ptr.o) + return val; + + if(ptr.o->type == UCI_TYPE_LIST) { + dmuci_print_list(&ptr.o->v.list, &val, " "); + return val; + } + + if (ptr.o->v.string) + return ptr.o->v.string; + else + return val; +} + +char *dmuci_get_value(char *package, char *section, char *option) +{ + struct uci_ptr ptr; + char *val = ""; + + if (!section || !option) + return val; + + if (dmuci_init_ptr(uci_ctx, &ptr, package, section, option, NULL)) { + return val; + } + if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK) { + return val; + } + + if (!ptr.o) + return val; + + if(ptr.o->type == UCI_TYPE_LIST) { + dmuci_print_list(&ptr.o->v.list, &val, " "); + return val; + } + + if (ptr.o->v.string) + return ptr.o->v.string; + else + return val; +} diff --git a/twamp/twampuci.h b/twamp/twampuci.h new file mode 100644 index 0000000..2523fd4 --- /dev/null +++ b/twamp/twampuci.h @@ -0,0 +1,33 @@ +/* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Copyright (C) 2019 iopsys Software Solutions AB +* Author: Amin Ben Ramdhane +*/ + +#ifndef _TWAMPUCI_H__ +#define _TWAMPUCI_H__ + +#include +#include +#include + + +int dmuci_init(void); +int dmuci_fini(void); +struct uci_section *dmuci_walk_section(char *package, char *section_type, struct uci_section *prev_section); +void dmuci_print_list(struct uci_list *uh, char **val, char *delimiter); +struct uci_element *dmuci_lookup_list(struct uci_list *list, const char *name); +int uci_lookup_ptr_bysection(struct uci_context *ctx, struct uci_ptr *ptr, struct uci_section *section, char *option, char *value); +char *dmuci_get_value_bysection(struct uci_section *section, char *option); +char *dmuci_get_value(char *package, char *section, char *option); + +#define dmuci_foreach_section(package, section_type, section) \ + for (section = dmuci_walk_section(package, section_type, NULL); \ + section != NULL; \ + section = dmuci_walk_section(package, section_type, section)) + +#endif /* _TWAMPUCI_H__ */