Compare commits

...

68 Commits

Author SHA1 Message Date
nevadita.chatterjee
6adf0e2837 map-topology added version 2020-10-07 17:40:08 +05:30
Sukru Senli
dd22c6ca12 icwmp: remove unnecessary parts from init script 2020-10-07 13:57:53 +02:00
vdutta
78700807de ieee1905: Fix crash in ex400 2020-10-07 16:44:33 +05:30
vdutta
3f689b5ed6 map-1905: Multiple fixes
- Change structure for countrycode in CAC capability
 - Fix segfault in timestamp tlv
2020-10-07 16:42:08 +05:30
Omar Kallel
cfa27af769 bbf: 2020-10-02 2020-10-02 11:37:43 +01:00
Omar Kallel
be5a00249e icwmp: 2020-10-02 2020-10-02 11:36:03 +01:00
Jakob Olsson
e22739cc8c wifimngr: 8.2.9 2020-10-01 15:29:20 +02:00
Jakob Olsson
239d1633e1 easy-soc-libs: 5.3.15 2020-10-01 10:46:17 +02:00
Rahul
342bec0b25 qosmngr: add support for traffic policing
Support for traffic policing added to allow configuration of
ingress rate limiting.

Test (on panther):
- ingress rate limiting on per lan port basis for US traffic.
- ingress rate limiting on wan port for DS traffic.
- when ingress rate limiting is applied on traffic in one direction,
  then traffic in other direction remains un-affected, that is, if
  ingress rate limiting is applied in DS, then US traffic on the port
  is unaffected

Note: Autotest are ready and will be merge for now with the tag not_ready.
Once devel is ready or if we decide to merge this to release-5.3, the same
can be tagged ready and executed as part of nightly suite.
2020-09-30 09:10:39 +02:00
Anjan Chanda
3942b33e1e wifimngr: 8.2.8 2020-09-29 21:51:19 +02:00
Anjan Chanda
3c3608e87c easy-soc-libs: 5.3.14 2020-09-29 21:51:04 +02:00
Amin Ben Ramdhane
aaf0029500 bbf: 2.4-2020-09-29 2020-09-29 19:20:14 +01:00
Amin Ben Ramdhane
7b80bcf104 icwmp: 5.0-2020-09-29 2020-09-29 19:18:18 +01:00
Raphael Derensy
f419a955f6 iop: select vsftpd-tls as module 2020-09-29 11:40:08 +02:00
Suru Dissanaike
d644ce7be6 iop: config, change rsync to module 2020-09-28 11:10:32 +02:00
Amin Ben Ramdhane
887ff49b95 bbf: 2.3-2020-09-26 2020-09-26 17:30:01 +01:00
Amin Ben Ramdhane
9c6533f45f bbf: 2.2-2020-09-24 2020-09-24 16:15:38 +01:00
Jakob Olsson
08f903e2c1 wifimngr: 8.2.7 2020-09-24 15:02:56 +02:00
Jakob Olsson
833837cea1 easy-soc-libs: 5.3.9 2020-09-24 15:01:22 +02:00
vdutta
dabf83ea1d uspd: B#3272 improvements in resolving paths 2020-09-24 13:48:33 +05:30
Anjan Chanda
0e6146f105 map-topology: 1.5.5 - notify topology change event 2020-09-24 09:33:04 +02:00
Amin Ben Ramdhane
220a4efbf7 Ticket refs #3228: QEMU - ICWMP is segfaulting
Fix missing objects
2020-09-23 19:21:14 +01:00
vdutta
e5d8d81019 ieee1905: Get auth mode from bss.security 2020-09-23 19:07:59 +05:30
vdutta
70442e891f ieee1905: Remove redundant info from ubus objects 2020-09-22 19:52:21 +05:30
Sukru Senli
ec021d54f5 iop: genconfig: comment out mediatek open parts 2020-09-22 12:33:08 +02:00
Amin Ben Ramdhane
421e633094 bbf: 2.1-2020-09-21 2020-09-21 18:16:25 +01:00
Jakob Olsson
068308f052 rearrange start orders for topology and ieee1905 2020-09-21 16:15:39 +02:00
Omar Kallel
8809a7aba7 bbf: fix segfault 2020-09-21 14:05:15 +02:00
Omar Kallel
7575dccbc0 icwmp: 5.0-2020-09-21 2020-09-21 14:04:53 +02:00
Jakob Olsson
871831fdac wfadatad: use service_running hook to wait for ieee1905 object 2020-09-21 09:12:27 +02:00
Amin Ben Ramdhane
db41d298c3 bbf: 2.0-2020-09-21 2020-09-21 09:09:54 +02:00
Jakob Olsson
ad372152d5 ieee1905: config trigger to reload 2020-09-21 09:01:11 +02:00
Jakob Olsson
926648b090 ieee1905: change start order from 99 to 13 2020-09-21 08:49:34 +02:00
Jakob Olsson
240bdc5bb8 wfadatad: wait up to 2 seconds if ieee1905 is not up before start 2020-09-21 08:49:14 +02:00
Amin Ben Ramdhane
45e0b4f2ed bbf: 2.0-2020-09-18 2020-09-18 15:19:14 +01:00
Jakob Olsson
332a90d087 map-topology: iterate til ieee1905 object is up 2020-09-18 16:13:32 +02:00
Anjan Chanda
09937f540a ieee1905d: enable map plugin in default config 2020-09-18 15:17:57 +02:00
Anjan Chanda
af8f27ef65 wfadatad: 2.3.0 2020-09-18 15:13:12 +02:00
Jakob Olsson
8a799f183b easy-soc-libs: libeasy: include debug.h 2020-09-18 14:34:00 +02:00
sverma
2dbf38c06c wfadatad: Changes UBUS objects name 2020-09-18 13:35:17 +02:00
Anjan Chanda
b1fcc12599 wifimngr: 8.2.3 2020-09-18 13:31:04 +02:00
Anjan Chanda
9041f616e7 easy-soc-libs: 5.3.3 2020-09-18 13:30:32 +02:00
Anjan Chanda
dc14b18428 map-topology: 1.5.1 2020-09-18 13:29:33 +02:00
Amin Ben Ramdhane
e41f973953 xmpp, udpecho, twamp: compile with fPIC 2020-09-18 12:07:17 +02:00
vdutta
9889814f0b uspd: Optimizations to reduce high cpu usages 2020-09-17 16:22:17 +05:30
Sukru Senli
2922f211f7 bulkdata: compile with fPIC 2020-09-16 10:02:59 +02:00
Sukru Senli
22dd43c79e icwmp: set userid empty in cwmp config; it will be filled by uci-default 2020-09-16 08:22:07 +02:00
Omar Kallel
478c34d48f icwmp: add the file /lib/upgrade/keep.d/icwmp when installing icwmp 2020-09-15 16:25:26 +02:00
Sukru Senli
49f46ef075 icwmp: 5.0-2020-09-15 2020-09-15 16:18:16 +02:00
Sukru Senli
03dc0ebb72 bbf: 2.0-2020-09-15 2020-09-15 16:11:15 +02:00
Sukru Senli
fa44657557 move trx69 packages out of trx69 folder 2020-09-14 18:28:00 +02:00
nevadita.chatterjee
42a3ed939a map-topology: Config file change 2020-09-14 18:27:00 +02:00
Markus Gothe
6e35356954 Fix gryphon LED module crash.
Update gryphon LED module to work with Linux 4.1
and not to crash when 'gpiod_get_index()' fails.

Change-Id: I27fcbe3ad9dbc755eabdd3f2120544b171b07885
2020-09-14 18:26:58 +02:00
Roman Azarenko
7978a656a7 iop: generate_tarballs: bcmkernel: add symlink if missing, partially fix shellcheck warnings 2020-09-14 18:26:56 +02:00
Sukru Senli
17322c3cba iop: config: select icwmp and bulkdata 2020-09-14 18:26:43 +02:00
Amin Ben Ramdhane
890b627139 icwmp: 5.0-2020-09-10 2020-09-14 18:22:21 +02:00
Amin Ben Ramdhane
0ad28b756b Ticket #2910: Separate BBF packages to their own packages with their own config files 2020-09-14 18:22:21 +02:00
Omar Kallel
309c26f4b0 icwmp: 09-09-2020 2020-09-14 18:22:21 +02:00
Omar Kallel
df4e11ae30 icwmp: Active notification 08/09/2020 2020-09-14 18:22:21 +02:00
Amin Ben Ramdhane
9de4a18a20 bbf: 2.0-2020-09-08 2020-09-14 18:22:21 +02:00
Sukru Senli
bfcc877a6a Revert "bbf: 1.9-2020-09-07"
This reverts commit 24a82ab61c.
2020-09-14 18:22:21 +02:00
Suru Dissanaike
d9527a5a1a icwmp: userid fix release, missing check if value is already present 2020-09-14 11:44:38 +02:00
Jakob Olsson
e707922d29 map-topology: override log func to supress prints 2020-09-14 09:06:53 +02:00
vdutta
cfc2e6d9eb obsupa: Increase ubus timeout to 10s 2020-09-11 16:52:41 +05:30
Jakob Olsson
0ec3e0eae8 map-topology: implement service discovery via dns-sd 2020-09-10 17:09:38 +02:00
Sukru Senli
38c4c7ded0 questd: 5.1.12: MAX_CLIENT increased to 256 2020-09-08 16:29:33 +02:00
Sukru Senli
24a82ab61c bbf: 1.9-2020-09-07 2020-09-08 12:55:20 +02:00
vdutta
5977ec807c uspd: Align with new gitlab ci 2020-09-08 15:47:23 +05:30
107 changed files with 11190 additions and 214 deletions

View File

@@ -5,11 +5,11 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=libbbfdm
PKG_VERSION:=1.9-2020-09-01
PKG_VERSION:=2.4-2020-10-02
PKG_FIXUP:=autoreconf
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/bbf.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=725981c900e0844107a857b53f636ae0a3a92eda
PKG_SOURCE_VERSION:=128e5b0900825eb8592cb1417a3b97af763930dc
PKG_RELEASE=$(PKG_SOURCE_VERSION)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)

44
bulkdata/Makefile Executable file
View File

@@ -0,0 +1,44 @@
#
# Copyright (C) 2020 iopsys Software Solutions AB
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=bulkdata
PKG_VERSION:=1.0.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=BBF BulkData Collection
DEPENDS:=+libubus +libuci +libubox +libjson-c +libcurl +curl +libblobmsg-json +libbbfdm +libbbf_api
endef
define Package/$(PKG_NAME)/description
BBF BulkData Collection
endef
define Build/Prepare
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += \
-D_GNU_SOURCE
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bulkdatad $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/usr/lib/bbfdm
$(INSTALL_BIN) $(PKG_BUILD_DIR)/*.so $(1)/usr/lib/bbfdm
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -0,0 +1,43 @@
config bulkdata 'bulkdata'
option enable '0'
#Log levels: Critical=0, Warning=1, Notice=2, Info=3, Debug=4
option log_level '3'
config profile
option profile_id '1'
option enable '0'
option name ''
option nbre_of_retained_failed_reports '0'
option protocol 'http'
option encoding_type ''
option reporting_interval '86400'
option time_reference '0'
option csv_encoding_field_separator ','
option csv_encoding_row_separator '
'
option csv_encoding_escape_character '"'
option csv_encoding_report_format 'column'
option csv_encoding_row_time_stamp 'unix'
option json_encoding_report_format 'objecthierarchy'
option json_encoding_report_time_stamp 'unix'
option http_url ''
option http_username ''
option http_password ''
option http_compression 'none'
option http_method 'post'
option http_use_date_header '1'
option http_retry_enable '0'
option http_retry_minimum_wait_interval '5'
option http_retry_interval_multiplier '2000'
option http_persist_across_reboot '0'
config profile_parameter
option profile_id '1'
option name ''
option reference ''
config profile_http_request_uri_parameter
option profile_id '1'
option name ''
option reference ''

View File

@@ -0,0 +1,34 @@
#!/bin/sh /etc/rc.common
# Bulkdata Software
# Copyright (C) 2020 iopsys Software Solutions AB
# Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
START=99
STOP=10
USE_PROCD=1
PROG="/usr/sbin/bulkdatad"
start_service() {
local bulkdata_enable=`uci -q get bulkdata.bulkdata.enable`
if [ "$bulkdata_enable" = "1" ]; then
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn "3" "7" "0"
procd_close_instance
fi
}
boot() {
start
}
reload_service() {
stop
start
}
service_triggers()
{
procd_add_reload_trigger bulkdata
}

23
bulkdata/src/Makefile Normal file
View File

@@ -0,0 +1,23 @@
PROG = bulkdatad
LIB = libbulkdata.so
PROG_OBJS = bulkdata.o common.o config.o http.o log.o report.o times.o buci.o
LIB_OBJS = datamodel.o
PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC
PROG_LDFLAGS = $(LDFLAGS) -lubus -luci -lubox -ljson-c -lcurl -lblobmsg_json -lbbfdm
LIB_LDFLAGS = $(LDFLAGS) -lbbf_api
%.o: %.c
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
all: $(PROG) $(LIB)
$(PROG): $(PROG_OBJS)
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
$(LIB): $(LIB_OBJS)
$(CC) $(PROG_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
clean:
rm -f *.o $(PROG) $(LIB)

265
bulkdata/src/buci.c Normal file
View File

@@ -0,0 +1,265 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include "buci.h"
struct uci_context *uci_ctx = NULL;
int buci_init(void)
{
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
return -1;
}
return 0;
}
int buci_fini(void)
{
if (uci_ctx) {
uci_free_context(uci_ctx);
}
return 0;
}
static bool buci_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 buci_init_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *package, char *section, char *option, char *value)
{
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 && !buci_validate_section(ptr->section))
ptr->flags |= UCI_LOOKUP_EXTENDED;
return 0;
error:
return -1;
}
struct uci_section *buci_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 (buci_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, *shead = NULL;
if (prev_section) {
ul = &prev_section->e.list;
shead = &prev_section->package->sections;
}
else {
if (buci_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 buci_print_list(struct uci_list *uh, char **val, char *delimiter)
{
struct uci_element *e;
static char buffer[512];
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 *buci_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 = buci_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 *buci_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) {
buci_print_list(&ptr.o->v.list, &val, " ");
return val;
}
if (ptr.o->v.string)
return ptr.o->v.string;
else
return val;
}
char *buci_get_value(char *package, char *section, char *option)
{
struct uci_ptr ptr;
char *val = "";
if (!section || !option)
return val;
if (buci_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) {
buci_print_list(&ptr.o->v.list, &val, " ");
return val;
}
if (ptr.o->v.string)
return ptr.o->v.string;
else
return val;
}

31
bulkdata/src/buci.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#ifndef __BUCI_H
#define __BUCI_H
#include <uci.h>
int buci_init(void);
int buci_fini(void);
struct uci_section *buci_walk_section(char *package, char *section_type, struct uci_section *prev_section);
void buci_print_list(struct uci_list *uh, char **val, char *delimiter);
struct uci_element *buci_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 *buci_get_value_bysection(struct uci_section *section, char *option);
char *buci_get_value(char *package, char *section, char *option);
#define buci_foreach_section(package, section_type, section) \
for (section = buci_walk_section(package, section_type, NULL); \
section != NULL; \
section = buci_walk_section(package, section_type, section))
#endif //__BUCI_H

144
bulkdata/src/bulkdata.c Normal file
View File

@@ -0,0 +1,144 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Omar Kallel <omar.kallel@pivasoftware.com>
*/
#include <stdio.h>
#include <string.h>
#include <libubox/uloop.h>
#include "http.h"
#include "config.h"
#include "log.h"
#include "common.h"
#include "report.h"
#include "times.h"
#include "bulkdata.h"
struct bulkdata bulkdata_main = {0};
int profiles_number = 0;
void bulkdata_profile_cb(struct uloop_timeout *timeout);
int get_retry_period(int min)
{
srand(time(NULL));
return rand()%min + min;
}
static void bulkdata_run_profiles(struct bulkdata *bulkdata)
{
unsigned int next_period;
int i = 0;
for (i = 0; i < profiles_number; i++) {
bulkdata->profile[i].utimer.cb = bulkdata_profile_cb;
LIST_HEAD(failedreports);
bulkdata->profile[i].failed_reports = &failedreports;
next_period = get_next_period(bulkdata->profile[i].time_reference, bulkdata->profile[i].reporting_interval);
bulkdata_log(SINFO, "The session of profile_id %d will be start in %d sec", bulkdata->profile[i].profile_id, next_period);
uloop_timeout_set(&bulkdata->profile[i].utimer, next_period * 1000);
}
}
int http_send_report(struct profile *profile, char *report)
{
char *msg_in = NULL;
int http_code;
http_client_init(profile);
bulkdata_log(SINFO, "Send the report of profile_id %d to Bulkdata Collector", profile->profile_id);
http_code = http_send_message(profile, report, strlen(report), &msg_in);
http_client_exit();
return http_code;
}
void bulkdata_profile_cb(struct uloop_timeout *timeout)
{
struct profile *profile;
unsigned int http_code, retry_period;
char *report = NULL;
profile = container_of(timeout, struct profile, utimer);
time_t now = time(NULL);
bulkdata_log(SINFO, "New session of profile_id %d started", profile->profile_id);
if(profile->retry_count == 0 || profile->next_retry > now || !profile->http_retry_enable) //Perdiodic execution
create_encoding_bulkdata_report(profile, &report);
else
create_failed_report(profile, &report);
bulkdata_log(SDEBUG, "The content of the profile_id report %d is :\n==========\n%s\n==========\n", profile->profile_id, report);
http_code= http_send_report(profile, report);
if(http_code != 200){
if(profile->retry_count == 0 || profile->next_retry > now || !profile->http_retry_enable) { //Perdiodic execution
retry_period = get_retry_period(profile->http_retry_minimum_wait_interval);
profile->next_period = now + profile->reporting_interval;
profile->next_retry = now + retry_period;
profile->retry_count = 1;
profile->min_retry = profile->http_retry_minimum_wait_interval * 2;
if((profile->next_retry < profile->next_period) && profile->http_retry_enable) {
bulkdata_log(SINFO, "Retry session of profile_id %d in %d sec", profile->profile_id, retry_period);
uloop_timeout_set(timeout, 1000 * retry_period);
}
else {
bulkdata_log(SINFO, "Start New session of profile_id %d in %d sec", profile->profile_id, profile->reporting_interval);
uloop_timeout_set(timeout, 1000 * profile->reporting_interval);
}
} else { //Retry execution
retry_period= get_retry_period(profile->min_retry);
profile->min_retry*=2;
profile->next_retry+=retry_period;
profile->retry_count++;
if(profile->next_retry < profile->next_period) {
bulkdata_log(SINFO, "Retry session of profile_id %d in %d sec", profile->profile_id, retry_period);
uloop_timeout_set(timeout, 1000 * retry_period);
}
else {
bulkdata_log(SINFO, "Retry session of profile_id %d in %d sec", profile->profile_id, (profile->next_period-profile->next_retry+retry_period));
uloop_timeout_set(timeout, 1000 * (profile->next_period-profile->next_retry+retry_period));
}
}
if(profile->new_report){
bulkdata_add_failed_report(profile, profile->new_report);
FREE(profile->new_report);
}
FREE(report);
} else {
if(profile->retry_count == 0 || profile->next_retry > now || !profile->http_retry_enable) {
bulkdata_log(SINFO, "Start New session of profile_id %d in %d sec", profile->profile_id, profile->reporting_interval);
uloop_timeout_set(timeout, 1000 * profile->reporting_interval);
}
else {
bulkdata_log(SINFO, "Retry session of profile_id %d in %d sec", profile->profile_id, (profile->next_period-profile->next_retry));
uloop_timeout_set(timeout, 1000 * (profile->next_period-profile->next_retry));
}
FREE(profile->new_report);
FREE(report);
empty_failed_reports_list(profile);
profile->retry_count= 0;
}
}
int main(void)
{
struct bulkdata *bulkdata = &bulkdata_main;
if (bulkdata_config_init(bulkdata) == -1)
return -1;
bulkdata_log(SINFO, "Start bulkdatad daemon");
uloop_init();
bulkdata_run_profiles(bulkdata);
uloop_run();
uloop_done();
bulkdata_config_fini(bulkdata);
bulkdata_log(SINFO, "Stop bulkdatad daemon");
return 0;
}

18
bulkdata/src/bulkdata.h Normal file
View File

@@ -0,0 +1,18 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#ifndef __BULKDATA_H
#define __BULKDATA_H
extern struct bulkdata bulkdata_main;
extern int profiles_number;
#endif /* __BULKDATA_H */

105
bulkdata/src/bulkdata.md Normal file
View File

@@ -0,0 +1,105 @@
# README #
bulkdatad is an implementation of The HTTP bulk data collection mechanism which is an extended feature of CPE and other agents implementing TR-069(CWMP) or TR-369(USP), defined by the Broadband Forum. It provides a means by which an Auto-Configuration Server (ACS), or USP Controller, can configure an agent to periodically send a JSON or CSV formatted set of Device information to an HTTP server running a data collection application.
## Configuration File ##
The bulkdatad UCI configuration is located in **'/etc/config/bulkdata'**, and contains 4 sections: **bulkdata**, **profile**, **profile\_parameter** and **profile\_http\_request\_uri\_parameter**.
```
config bulkdata 'bulkdata'
option enable '0'
option log_level '3'
config profile
option profile_id '1'
option enable '0'
option csv_encoding_row_time_stamp 'unix'
option json_encoding_report_time_stamp 'unix'
option http_retry_minimum_wait_interval '5'
option http_retry_interval_multiplier '2000'
config profile_parameter
option profile_id '1'
option name ''
option reference ''
config profile_http_request_uri_parameter
option profile_id '1'
option name ''
option reference ''
```
### bulkdata section ###
It defines **bulkdata configuration**: enable and log\_level.
| Name | Type | Description |
| ----------- | ------- | ----------------------------------------------------------------------------------------------- |
| `enable` | boolean | Enables the BulkData feature if set to **1**. |
| `log_level` | integer | Specifies the log type to use, by default **'INFO'**. The possible types are **'EMERG', 'ALERT', 'CRITIC' ,'ERROR', 'WARNING', 'NOTICE', 'INFO' and 'DEBUG'**. |
### profile section ###
It defines **the profile section configuration**: enable, name,... The possible options for **profile** section are listed below:
| Name | Type | Description |
| ---------------------------------- | ------- | ---------------------------------------------- |
| `profile_id` | integer | The profile id to use. |
| `enable` | boolean | If set to **1**, enables the bulkdata profile. |
| `name` | string | The name of the profile. |
| `nbre_of_retained_failed_reports` | integer | The number of failed reports to be retained and transmitted at the end of the current reporting interval. |
| `protocol` | string | The protocol used for the collection profile. |
| `encoding_type` | string | The encoding type used for the collection profile. |
| `reporting_interval` | integer | The reporting interval in seconds. |
| `time_reference` | integer | The time reference to determine when the profile will be transmitted to the ACS collector. |
| `csv_encoding_field_separator` | string | The field separator to use when encoding CSV data. |
| `csv_encoding_row_separator` | string | The row separator to use when encoding CSV data. |
| `csv_encoding_escape_character` | string | The escape character to use when encoding CSV data. |
| `csv_encoding_report_format` | string | Describes how reports will be formatted. Two possible formats are supported: **'ParameterPerRow' and 'ParameterPerColumn'**. |
| `csv_encoding_row_time_stamp` | string | The format of the timestamp to use for data inserted into the row. The row time stamp supported are **'Unix-Epoch', 'ISO-8601' and 'None'**. |
| `json_encoding_report_format` | string | Describes the report format. The supported report formats are **'ObjectHierarchy' and 'NameValuePair'**. |
| `json_encoding_report_time_stamp` | string | The format of the timestamp to use for the JSON Object named "CollectionTime". The supported timestamp are **'Unix-Epoch', 'ISO-8601' and 'None'**. |
| `http_url` | string | The URL of the collection server. |
| `http_username` | string | The username of the collection server. |
| `http_password` | string | The password of the collection server. |
| `http_compression` | string | The HTTP Compression mechanism used by the collection server. The supported compression mechanism are **'GZIP', 'Compress' and 'Deflate'**. |
| `http_method` | string | The HTTP method used by the collection server. Two methods are supported: **'POST' and 'PUT'**. |
| `http_use_date_header` | boolean | If set to **1**, the CPE encodes the HTTP Date Header. |
| `http_retry_enable` | boolean | If set to **1**, the CPE retries unsuccessful attempts to transfer data. |
| `http_retry_minimum_wait_interval` | integer | The data transfer retry wait interval. |
| `http_retry_interval_multiplier` | integer | The retry interval multiplier. |
| `http_persist_across_reboot` | boolean | If set to **1**, failed data transfers must be persisted across reboots. |
### profile_parameter section ###
It defines **the profile\_parameter section configuration**: profile\_id, name, reference.
| Name | Type | Description |
| ------------ | ------- | --------------------------------------- |
| `profile_id` | integer | The id of the used profile. |
| `name` | string | The name of the profile parameter. |
| `reference` | string | The reference of the profile parameter. |
### profile_http_request_uri_parameter section ###
It defines **the profile\_http\_request\_uri\_parameter section configuration**: profile\_id, name, reference.
| Name | Type | Description |
| ------------ | ------- | --------------------------------------- |
| `profile_id` | integer | The id of the used profile. |
| `name` | string | The name of the Request-URI parameter. |
| `reference` | string | The reference of the profile parameter. |
## Dependencies ##
To successfully build bulkdatad, the following libraries are needed:
| Dependency | Link | License |
| ----------- | ------------------------------------------- | -------------- |
| libuci | https://git.openwrt.org/project/uci.git | LGPL 2.1 |
| libubox | https://git.openwrt.org/project/libubox.git | BSD |
| libjson-c | https://s3.amazonaws.com/json-c_releases | MIT |
| libcurl | https://dl.uxnr.de/mirror/curl | MIT |
| libbbfdm | https://dev.iopsys.eu/iopsys/bbf.git | LGPL 2.1 |

450
bulkdata/src/common.c Normal file
View File

@@ -0,0 +1,450 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Omar Kallel <omar.kallel@pivasoftware.com>
*/
#include "common.h"
static pathnode *head = NULL;
static pathnode *temphead = NULL;
int bulkdata_dm_ctx_init(struct dmctx *ctx)
{
struct bulkdata *bulkdata = &bulkdata_main;
dm_ctx_init(ctx, DM_CWMP, bulkdata->amd_version, bulkdata->instance_mode);
return 0;
}
int bulkdata_dm_ctx_clean(struct dmctx *ctx)
{
dm_ctx_clean(ctx);
return 0;
}
static char **str_split(const char* str, const char* delim, size_t* numtokens)
{
char *s = strdup(str);
size_t tokens_alloc = 1;
size_t tokens_used = 0;
char **tokens = calloc(tokens_alloc, sizeof(char*));
char *token, *strtok_ctx;
for (token = strtok_r(s, delim, &strtok_ctx); token != NULL; token = strtok_r(NULL, delim, &strtok_ctx)) {
if (tokens_used == tokens_alloc) {
tokens_alloc *= 2;
tokens = realloc(tokens, tokens_alloc * sizeof(char*));
}
tokens[tokens_used++] = strdup(token);
}
// cleanup
if (tokens_used == 0) {
FREE(tokens);
} else {
tokens = realloc(tokens, tokens_used * sizeof(char*));
}
*numtokens = tokens_used;
FREE(s);
return tokens;
}
static bool bulkdata_match(const char *string, const char *pattern)
{
regex_t re;
if (regcomp(&re, pattern, REG_EXTENDED) != 0) return 0;
int status = regexec(&re, string, 0, NULL, 0);
regfree(&re);
if (status != 0) return false;
return true;
}
static bool is_res_required(char *str, int *start, int *len)
{
char temp_char[NAME_MAX] = {'\0'};
if (bulkdata_match(str, GLOB_CHAR)) {
int s_len = strlen(str);
int b_len = s_len, p_len = s_len;
char *star = strchr(str, '*');
if(star)
s_len = star - str;
*start = MIN(MIN(s_len, p_len), b_len);
if (*start == s_len)
*len = 1;
strncpy(temp_char, str+*start, *len);
if (bulkdata_match(temp_char, "[*+]+"))
return true;
}
*start = strlen(str);
return false;
}
static void insert(char *data, bool active)
{
pathnode *link = (pathnode*) calloc(1, sizeof(pathnode));
if(!link) {
return;
}
link->ref_path = data;
if(active) {
link->next = head;
head = link;
} else {
link->next = temphead;
temphead = link;
}
}
static void swap_heads(void)
{
pathnode *temp = head;
head = temphead;
temphead = temp;
}
static void deleteList(void)
{
pathnode *ptr = head, *temp;
while(ptr != NULL) {
temp = ptr;
free(ptr->ref_path);
if(ptr->next != NULL) {
ptr = ptr->next;
} else {
ptr = NULL;
}
free(temp);
}
head = NULL;
swap_heads();
}
void bulkdata_add_data_to_list(struct list_head *dup_list, char *name, char *value, char *type)
{
struct resultsnode *link;
link = calloc(1, sizeof(struct resultsnode));
list_add_tail(&link->list, dup_list);
link->name = strdup(name);
link->data = strdup(value);
link->type = strdup(type);
}
void bulkdata_delete_data_from_list(struct resultsnode *link)
{
list_del(&link->list);
FREE(link->name);
FREE(link->data);
FREE(link->type);
FREE(link);
}
void bulkdata_free_data_from_list(struct list_head *dup_list)
{
struct resultsnode *link;
while (dup_list->next != dup_list) {
link = list_entry(dup_list->next, struct resultsnode, list);
bulkdata_delete_data_from_list(link);
}
}
static bool bulkdata_get(int operation, char *path, struct dmctx *dm_ctx)
{
int fault = 0;
switch(operation) {
case CMD_GET_NAME:
fault = dm_entry_param_method(dm_ctx, CMD_GET_NAME, path, "true", NULL);
break;
case CMD_GET_VALUE:
fault = dm_entry_param_method(dm_ctx, CMD_GET_VALUE, path, NULL, NULL);
break;
default:
return false;
}
if (dm_ctx->list_fault_param.next != &dm_ctx->list_fault_param) {
return false;
}
if (fault) {
return false;
}
return true;
}
char *bulkdata_get_value_param(char *path)
{
struct dmctx ctx = {0};
struct dm_parameter *n;
char *value = NULL;
bulkdata_dm_ctx_init(&ctx);
if(bulkdata_get(CMD_GET_VALUE, path, &ctx)) {
list_for_each_entry(n, &ctx.list_parameter, list) {
value = strdup(n->data);
break;
}
}
bulkdata_dm_ctx_clean(&ctx);
return value;
}
void bulkdata_get_value(char *path, struct list_head *list)
{
struct dmctx ctx = {0};
struct dm_parameter *n;
bulkdata_dm_ctx_init(&ctx);
if(bulkdata_get(CMD_GET_VALUE, path, &ctx)) {
list_for_each_entry(n, &ctx.list_parameter, list) {
bulkdata_add_data_to_list(list, n->name, n->data, n->type);
}
}
bulkdata_dm_ctx_clean(&ctx);
}
bool bulkdata_get_name(char *path)
{
struct dmctx ctx = {0};
struct dm_parameter *n;
bool ret = false;
bulkdata_dm_ctx_init(&ctx);
if(bulkdata_get(CMD_GET_NAME, path, &ctx)) {
list_for_each_entry(n, &ctx.list_parameter, list) {
insert(strdup(n->name), false);
}
ret = true;
}
bulkdata_dm_ctx_clean(&ctx);
return ret;
}
static void fill_node_path(void)
{
pathnode *p=head;
while(p!=NULL) {
bulkdata_get_name(p->ref_path);
p=p->next;
}
deleteList();
}
static void bulkdata_filter_results(char *path, int start, int end)
{
int startpos = start, m_index = 0, m_len = 0;
char *pp = path + startpos;
char exp[NAME_MAX] = {'\0'};
if(start >= end) {
return;
}
if(!is_res_required(pp, &m_index, &m_len)) {
//append rest of the path to the final list
if(pp == path ) {
insert(strdup(pp), true);
return;
}
pathnode *p = head;
while(p != NULL) {
char name[NAME_MAX] = {'\0'};
strcpy(name, p->ref_path);
strcat(name, pp);
insert(strdup(name), false);
p = p->next;
}
deleteList();
return;
}
// Get the string before the match
char name[NAME_MAX]={'\0'};
strncpy(name, pp, m_index);
pathnode *p = head;
if(p == NULL) {
insert(strdup(name), false);
}
while(p != NULL) {
char ref_name[NAME_MAX] = {'\0'};
sprintf(ref_name, "%s%s", p->ref_path, name);
insert(strdup(ref_name), false);
p = p->next;
}
deleteList();
startpos += m_index;
strncpy(exp, pp+m_index, m_len);
pp = path + startpos;
fill_node_path();
startpos += 2;
bulkdata_filter_results(path, startpos, end);
}
static void bulkdata_parse_results(struct list_head *list)
{
pathnode *p = head;
while(p != NULL) {
bulkdata_get_value(p->ref_path, list);
p = p->next;
}
deleteList();
}
void bulkdata_get_value_results(char *path, struct list_head *list)
{
bulkdata_filter_results(path, 0, strlen(path));
bulkdata_parse_results(list);
}
char *create_request_url(struct profile *profile)
{
int i = 0, http_uri_number = profile->profile_http_request_uri_parameter_number;
char *value, *uri_param = NULL, *uri_tmp = NULL, *http_url = NULL;
for (i = 0; i < http_uri_number; i++)
{
if((profile->profile_http_uri_parameter[i].reference == NULL) || (profile->profile_http_uri_parameter[i].name == NULL))
continue;
value = bulkdata_get_value_param(profile->profile_http_uri_parameter[i].reference);
if(!uri_param) {
asprintf(&uri_param, "&%s=%s", profile->profile_http_uri_parameter[i].name, value);
free(value);
}
else {
uri_tmp = strdup(uri_param);
free(uri_param);
asprintf(&uri_param, "%s&%s=%s", uri_tmp, profile->profile_http_uri_parameter[i].name, value);
free(value);
free(uri_tmp);
}
}
if(uri_param) {
asprintf(&http_url, "%s%s", profile->http_url, uri_param);
free(uri_param);
} else {
asprintf(&http_url, "%s", profile->http_url);
}
return http_url;
}
char *get_bulkdata_profile_parameter_name(char *paramref, char *paramname, char *param)
{
char **paramarr, *idx1 = NULL, *idx2 = NULL, *res = NULL, *instance = NULL, *tmp = NULL, *retparam = NULL, *s = NULL;
int i, j = 0;
size_t length;
if(paramname == NULL || strlen(paramname) <= 0)
return strdup(param);
paramarr = str_split(paramref, "*", &length);
res = strdup(paramname);
for(i = 0; i < length; i++) {
if(i == length - 1)
break;
j++;
idx1 = strstr(param, paramarr[i]);
idx2 = strstr(param, paramarr[i+1]);
instance = (char*)calloc(idx2 - idx1 - strlen(paramarr[i]) + 1, sizeof(char));
memcpy(instance, idx1 + strlen(paramarr[i]), idx2 - idx1 - strlen(paramarr[i]));
tmp = strdup(res);
FREE(res);
asprintf(&res, "%s.%s", tmp, instance);
FREE(tmp);
FREE(instance);
}
if ((s = strstr(param,paramarr[j]) ) != NULL && strlen(s) == strlen(paramarr[j]))
asprintf(&retparam, "%s", res);
else
asprintf(&retparam, "%s.%s", res, strstr(param, paramarr[j]) + strlen(paramarr[j]));
FREE(res);
for(int k = 0; k < length; k++)
FREE(paramarr[k]);
FREE(paramarr);
return retparam;
}
void append_string_to_string(char *strappend, char **target)
{
char *tmp = NULL;
if(strappend == NULL || strlen(strappend) <= 0)
return;
if(*target == NULL || strlen(*target) <= 0) {
*target = strdup(strappend);
return;
} else {
tmp = strdup(*target);
FREE(*target);
}
asprintf(target, "%s%s", tmp, strappend);
FREE(tmp);
}
void bulkdata_add_failed_report(struct profile *profile, char *freport)
{
struct failed_reports *report, *retreport, *rtmp;
if(profile->nbre_failed_reports < profile->nbre_of_retained_failed_reports || profile->nbre_of_retained_failed_reports < 0) {
profile->nbre_failed_reports++;
} else {
list_for_each_entry_safe(retreport, rtmp, profile->failed_reports, list) {
bulkdata_delete_failed_report(retreport);
break;
}
}
report = calloc(1, sizeof(struct failed_reports));
list_add_tail(&report->list, profile->failed_reports);
report->freport= strdup(freport);
}
void bulkdata_delete_failed_report(struct failed_reports *report)
{
if(report != NULL) {
list_del(&report->list);
FREE(report->freport);
FREE(report);
}
}
struct failed_reports* empty_failed_reports_list(struct profile *profile)
{
struct failed_reports *report, *rtmp;
if(list_empty(profile->failed_reports))
return NULL;
list_for_each_entry_safe(report, rtmp, profile->failed_reports, list) {
list_del(&report->list);
FREE(report->freport);
FREE(report);
}
return NULL;
}
void add_failed_reports_to_report_csv(struct profile *profile, char **report, int isnext)
{
struct failed_reports *retreport = NULL;
int j = 0;
if(list_empty(profile->failed_reports))
return;
list_for_each_entry(retreport, profile->failed_reports, list) {
if(!j && isnext) {
j = 1;
continue;
}
append_string_to_string(retreport->freport, report);
}
}

69
bulkdata/src/common.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#ifndef __COMMON_H
#define __COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <regex.h>
#include <sys/param.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <libubox/utils.h>
#include <libubus.h>
#include <libbbfdm/dmentry.h>
#include <libbbfdm/dmbbfcommon.h>
#include "config.h"
#include "log.h"
#include "bulkdata.h"
typedef struct pathnode {
char *ref_path;
struct pathnode *next;
} pathnode;
typedef struct resultsnode {
struct list_head list;
char *name;
char *data;
char *type;
} resultsnode;
struct failed_reports {
struct list_head list;
char *freport;
};
#define GLOB_CHAR "[[+*]+"
int bulkdata_dm_ctx_init(struct dmctx *ctx);
int bulkdata_dm_ctx_clean(struct dmctx *ctx);
char *bulkdata_get_value_param(char *path);
void bulkdata_get_value(char *path, struct list_head *list);
void bulkdata_free_data_from_list(struct list_head *dup_list);
void bulkdata_get_value_results(char *path, struct list_head *list);
char *create_request_url(struct profile *profile);
char *get_bulkdata_profile_parameter_name(char *paramref, char *paramname, char *param);
void append_string_to_string(char *strappend, char **target);
void bulkdata_add_failed_report(struct profile *profile, char *freport);
void bulkdata_delete_failed_report(struct failed_reports *report);
struct failed_reports *empty_failed_reports_list(struct profile *profile);
void add_failed_reports_to_report_csv(struct profile *profile, char **report, int isnext);
#endif //__COMMON_H

524
bulkdata/src/config.c Normal file
View File

@@ -0,0 +1,524 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Omar Kallel <omar.kallel@pivasoftware.com>
*/
#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <libbbfdm/deviceinfo.h>
#include "log.h"
#include "config.h"
#include "buci.h"
#include "common.h"
#include "bulkdata.h"
int get_log_level_config(struct bulkdata *bulkdata)
{
char *value = NULL;
buci_init();
value = buci_get_value("bulkdata", "bulkdata", "log_level");
if(value != NULL && *value != '\0')
bulkdata->log_level = atoi(value);
else
bulkdata->log_level = DEFAULT_LOGLEVEL;
bulkdata_log(SDEBUG,"Log Level of Bulkdata is : %d", bulkdata->log_level);
buci_fini();
return 0;
}
int get_amd_version_config(struct bulkdata *bulkdata)
{
char *value = NULL;
buci_init();
value = buci_get_value("cwmp", "cpe", "amd_version");
if(value != NULL && *value != '\0')
bulkdata->amd_version = atoi(value);
else
bulkdata->amd_version = DEFAULT_AMD_VERSION;
bulkdata_log(SDEBUG,"CWMP Amendment Version is : %d", bulkdata->amd_version);
buci_fini();
return 0;
}
int get_instance_mode_config(struct bulkdata *bulkdata)
{
char *value = NULL;
buci_init();
value = buci_get_value("cwmp", "cpe", "instance_mode");
if(value != NULL && *value != '\0') {
if(!strcmp(value, "InstanceNumber"))
bulkdata->instance_mode = INSTANCE_MODE_NUMBER;
else
bulkdata->instance_mode = INSTANCE_MODE_ALIAS;
}
else
bulkdata->instance_mode = DEFAULT_INSTANCE_MODE;
bulkdata_log(SDEBUG,"CWMP Instance Mode is : %d", bulkdata->instance_mode);
buci_fini();
return 0;
}
int get_device_id_config(struct bulkdata *bulkdata)
{
struct dmctx dmctx = {0};
bulkdata_dm_ctx_init(&dmctx);
bulkdata->device_id.manufacturer_oui = strdup(get_deviceid_manufactureroui());
bulkdata->device_id.product_class = strdup(get_deviceid_productclass());
bulkdata->device_id.serial_number = strdup(get_deviceid_serialnumber());
bulkdata_dm_ctx_clean(&dmctx);
return 0;
}
int load_profile_config(struct bulkdata *bulkdata, struct uci_section *s, int i)
{
char *value = NULL;
value = buci_get_value_bysection(s, "profile_id");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].profile_id = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The profile_id of profile_id %d is : %d", i, bulkdata->profile[i].profile_id);
} else
return -1;
value = buci_get_value_bysection(s, "nbre_of_retained_failed_reports");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].nbre_of_retained_failed_reports = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The nombre of retained failed reports of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].nbre_of_retained_failed_reports);
}
value = buci_get_value_bysection(s, "protocol");
if(value != NULL && *value != '\0' && strcasecmp(value, "http")==0) {
bulkdata->profile[i].protocol = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The protocol of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].protocol);
} else
return -1;
value = buci_get_value_bysection(s, "encoding_type");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].encoding_type = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The encoding type of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].encoding_type);
} else
return -1;
value = buci_get_value_bysection(s, "reporting_interval");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].reporting_interval = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The reporting interval of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].reporting_interval);
} else
return -1;
value = buci_get_value_bysection(s, "time_reference");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].time_reference = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The time reference of profile_id %d is : %ld", bulkdata->profile[i].profile_id, bulkdata->profile[i].time_reference);
} else
return -1;
value = buci_get_value_bysection(s, "csv_encoding_field_separator");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].csv_encoding_field_separator = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The csv encoding field separator of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].csv_encoding_field_separator);
} else
return -1;
value = buci_get_value_bysection(s, "csv_encoding_row_separator");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].csv_encoding_row_separator = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The csv encoding row separator of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].csv_encoding_row_separator);
} else
return -1;
value = buci_get_value_bysection(s, "csv_encoding_escape_character");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].csv_encoding_escape_character = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The csv encoding escape character of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].csv_encoding_escape_character);
}
value = buci_get_value_bysection(s, "csv_encoding_report_format");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].csv_encoding_report_format = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The csv encoding report format of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].csv_encoding_report_format);
} else
return -1;
value = buci_get_value_bysection(s, "csv_encoding_row_time_stamp");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].csv_encoding_row_time_stamp = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The csv encoding row time stamp of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].csv_encoding_row_time_stamp);
} else
return -1;
value = buci_get_value_bysection(s, "json_encoding_report_format");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].json_encoding_report_format = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The json encoding report format of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].json_encoding_report_format);
} else
return -1;
value = buci_get_value_bysection(s, "json_encoding_report_time_stamp");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].json_encoding_report_time_stamp = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The json encoding report time stamp of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].json_encoding_report_time_stamp);
} else
return -1;
value = buci_get_value_bysection(s, "http_url");
if(value != NULL && *value != '\0') {
char *url = NULL;
asprintf(&url, "%s?oui=%s&pc=%s&sn=%s", value, bulkdata->device_id.manufacturer_oui, bulkdata->device_id.serial_number, bulkdata->device_id.serial_number);
bulkdata->profile[i].http_url = strdup(url);
free(url);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP url of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_url);
} else
return -1;
value = buci_get_value_bysection(s, "http_username");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_username = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP username of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_username);
} else {
bulkdata->profile[i].http_username = NULL;
}
value = buci_get_value_bysection(s, "http_password");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_password = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP password of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_password);
} else {
bulkdata->profile[i].http_password = NULL;
}
value = buci_get_value_bysection(s, "http_compression");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_compression = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP compression of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_compression);
} else
return -1;
value = buci_get_value_bysection(s, "http_method");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_method = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP method of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_method);
} else
return -1;
value = buci_get_value_bysection(s, "http_use_date_header");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_use_date_header = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP use date header of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_use_date_header);
}
value = buci_get_value_bysection(s, "http_retry_enable");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_retry_enable = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP retry enable of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_retry_enable);
} else
return -1;
value = buci_get_value_bysection(s, "http_retry_minimum_wait_interval");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_retry_minimum_wait_interval = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP retry minimum wait interval of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_retry_minimum_wait_interval);
}
value = buci_get_value_bysection(s, "http_retry_interval_multiplier");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_retry_interval_multiplier = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP retry interval multiplier of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_retry_interval_multiplier);
}
value = buci_get_value_bysection(s, "http_persist_across_reboot");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_persist_across_reboot = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP persist across reboot of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_persist_across_reboot);
} else
return -1;
value = buci_get_value_bysection(s, "http_ssl_capath");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_ssl_capath = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP ssl capath of profile_id %d is : %s", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_ssl_capath);
} else {
bulkdata->profile[i].http_ssl_capath = NULL;
}
value = buci_get_value_bysection(s, "http_insecure_enable");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].http_insecure_enable = atoi(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP insecure enable of profile_id %d is : %d", bulkdata->profile[i].profile_id, bulkdata->profile[i].http_insecure_enable);
}
bulkdata->profile[i].retry_count = 0;
bulkdata->profile[i].nbre_failed_reports = 0;
return 0;
}
int get_profiles_enable(struct bulkdata *bulkdata)
{
struct uci_section *s;
char *enable;
int i = 0, nbr_profiles = 0;
buci_init();
buci_foreach_section("bulkdata", "profile", s) {
enable = buci_get_value_bysection(s, "enable");
if(strcmp(enable, "1") == 0) {
nbr_profiles++;
}
}
if(nbr_profiles != 0)
bulkdata->profile = calloc(2, sizeof(struct profile));
buci_foreach_section("bulkdata", "profile", s) {
enable = buci_get_value_bysection(s, "enable");
if(strcmp(enable, "1") == 0) {
if(load_profile_config(bulkdata, s, i) == -1) {
bulkdata_log(SCRIT,"Not able to start bulkdata: some required bulkdata configurations in profile must be set");
return -1;
}
i++;
}
}
profiles_number = nbr_profiles;
buci_fini();
return 0;
}
int load_profile_parameter_config(struct bulkdata *bulkdata, struct uci_section *s, int i, int j)
{
char *value = NULL;
value = buci_get_value_bysection(s, "name");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].profile_parameter[j].name = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The parameter name %d of profile_id %d is : %s", j+1, bulkdata->profile[i].profile_id, bulkdata->profile[i].profile_parameter[j].name);
} else {
bulkdata->profile[i].profile_parameter[j].name = NULL;
}
value = buci_get_value_bysection(s, "reference");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].profile_parameter[j].reference = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The parameter reference %d of profile_id %d is : %s", j+1, bulkdata->profile[i].profile_id, bulkdata->profile[i].profile_parameter[j].reference);
} else
return -1;
return 0;
}
int get_profiles_parameters(struct bulkdata *bulkdata)
{
struct uci_section *s;
char *profile_id;
int i, j, nbr_profile_parameters;
buci_init();
for (i = 0; i < profiles_number; i++) {
j = 0;
nbr_profile_parameters = 0;
buci_foreach_section("bulkdata", "profile_parameter", s) {
profile_id = buci_get_value_bysection(s, "profile_id");
if(bulkdata->profile[i].profile_id != atoi(profile_id))
continue;
nbr_profile_parameters++;
if(nbr_profile_parameters == 1) {
bulkdata->profile[i].profile_parameter = calloc(1, sizeof(struct profile_parameter));
} else {
bulkdata->profile[i].profile_parameter = realloc(bulkdata->profile[i].profile_parameter, nbr_profile_parameters * sizeof(struct profile_parameter));
}
if(load_profile_parameter_config(bulkdata, s, i, j) == -1) {
bulkdata_log(SCRIT,"Not able to start bulkdata: some required bulkdata configurations in profile_parameter must be set");
return -1;
}
j++;
}
bulkdata->profile[i].profile_parameter_number = nbr_profile_parameters;
}
buci_fini();
return 0;
}
int load_profile_http_request_uri_parameter_config(struct bulkdata *bulkdata, struct uci_section *s, int i, int j)
{
char *value = NULL;
value = buci_get_value_bysection(s, "name");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].profile_http_uri_parameter[j].name = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP resuest URI parameter name %d of profile_id %d is : %s", j+1, bulkdata->profile[i].profile_id, bulkdata->profile[i].profile_http_uri_parameter[j].name);
} else
return -1;
value = buci_get_value_bysection(s, "reference");
if(value != NULL && *value != '\0') {
bulkdata->profile[i].profile_http_uri_parameter[j].reference = strdup(value);
value = NULL;
bulkdata_log(SDEBUG,"The HTTP resuest URI parameter reference %d of profile_id %d is : %s", j+1, bulkdata->profile[i].profile_id, bulkdata->profile[i].profile_http_uri_parameter[j].reference);
} else
return -1;
return 0;
}
int get_profile_http_request_uri_parameter(struct bulkdata *bulkdata)
{
struct uci_section *s;
char *profile_id;
int i, j, nbr_profile_http_request_uri_parameter;
buci_init();
for (i = 0; i < profiles_number; i++) {
j = 0;
nbr_profile_http_request_uri_parameter = 0;
buci_foreach_section("bulkdata", "profile_http_request_uri_parameter", s) {
profile_id = buci_get_value_bysection(s, "profile_id");
if(bulkdata->profile[i].profile_id != atoi(profile_id))
continue;
nbr_profile_http_request_uri_parameter++;
if(nbr_profile_http_request_uri_parameter == 1) {
bulkdata->profile[i].profile_http_uri_parameter = calloc(1, sizeof(struct profile_http_request_uri_parameter));
} else {
bulkdata->profile[i].profile_http_uri_parameter = realloc(bulkdata->profile[i].profile_http_uri_parameter, nbr_profile_http_request_uri_parameter * sizeof(struct profile_http_request_uri_parameter));
}
if(load_profile_http_request_uri_parameter_config(bulkdata, s, i, j)== -1) {
bulkdata_log(SCRIT,"Not able to start bulkdata: some required bulkdata configurations in profile_http_request_uri_parameter must be set");
return -1;
}
j++;
}
bulkdata->profile[i].profile_http_request_uri_parameter_number = nbr_profile_http_request_uri_parameter;
}
buci_fini();
return 0;
}
int bulkdata_config_init(struct bulkdata *bulkdata)
{
get_log_level_config(bulkdata);
get_amd_version_config(bulkdata);
get_instance_mode_config(bulkdata);
get_device_id_config(bulkdata);
if (get_profiles_enable(bulkdata) == -1)
return -1;
if (get_profiles_parameters(bulkdata) == -1)
return -1;
if (get_profile_http_request_uri_parameter(bulkdata) == -1)
return -1;
return 0;
}
int free_device_id_config(struct bulkdata *bulkdata)
{
FREE(bulkdata->device_id.manufacturer_oui);
FREE(bulkdata->device_id.product_class);
FREE(bulkdata->device_id.serial_number);
return 0;
}
int free_profiles_enable(struct bulkdata *bulkdata)
{
for(int i = 0; i < profiles_number; i++) {
FREE(bulkdata->profile[i].protocol);
FREE(bulkdata->profile[i].encoding_type);
FREE(bulkdata->profile[i].csv_encoding_field_separator);
FREE(bulkdata->profile[i].csv_encoding_row_separator);
FREE(bulkdata->profile[i].csv_encoding_escape_character);
FREE(bulkdata->profile[i].csv_encoding_report_format);
FREE(bulkdata->profile[i].csv_encoding_row_time_stamp);
FREE(bulkdata->profile[i].json_encoding_report_format);
FREE(bulkdata->profile[i].json_encoding_report_time_stamp);
FREE(bulkdata->profile[i].http_url);
FREE(bulkdata->profile[i].http_username);
FREE(bulkdata->profile[i].http_password);
FREE(bulkdata->profile[i].http_compression);
FREE(bulkdata->profile[i].http_method);
FREE(bulkdata->profile[i].http_ssl_capath);
}
FREE(bulkdata->profile);
return 0;
}
int free_profiles_parameters(struct bulkdata *bulkdata)
{
for(int i = 0; i < profiles_number; i++) {
for(int j = 0; j < bulkdata->profile[i].profile_parameter_number; j++) {
FREE(bulkdata->profile[i].profile_parameter[j].name);
FREE(bulkdata->profile[i].profile_parameter[j].reference);
}
FREE(bulkdata->profile[i].profile_parameter);
}
return 0;
}
int free_profile_http_request_uri_parameter(struct bulkdata *bulkdata)
{
for(int i = 0; i < profiles_number; i++) {
for(int j = 0; j < bulkdata->profile[i].profile_http_request_uri_parameter_number; j++) {
FREE(bulkdata->profile[i].profile_http_uri_parameter[j].name);
FREE(bulkdata->profile[i].profile_http_uri_parameter[j].reference);
}
FREE(bulkdata->profile[i].profile_http_uri_parameter);
}
return 0;
}
int bulkdata_config_fini(struct bulkdata *bulkdata)
{
free_device_id_config(bulkdata);
free_profiles_parameters(bulkdata);
free_profile_http_request_uri_parameter(bulkdata);
free_profiles_enable(bulkdata);
return 0;
}

103
bulkdata/src/config.h Normal file
View File

@@ -0,0 +1,103 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#ifndef __CONFIG_H
#define __CONFIG_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <libubox/uloop.h>
#define DEFAULT_AMD_VERSION 2
#define DEFAULT_INSTANCE_MODE 0
typedef struct device_id {
char *manufacturer_oui;
char *product_class;
char *serial_number;
} device_id;
typedef struct profile_parameter {
int profile_id;
char *name;
char *reference;
} profile_parameter;
typedef struct profile_http_request_uri_parameter {
int profile_id;
char *name;
char *reference;
} profile_http_request_uri_parameter;
typedef struct profile {
struct uloop_timeout utimer;
int profile_id;
int nbre_of_retained_failed_reports;
int nbre_failed_reports;
int reporting_interval;
int profile_parameter_number;
int profile_http_request_uri_parameter_number;
int http_retry_minimum_wait_interval;
int http_retry_interval_multiplier;
int min_retry;
int retry_count;
char *protocol;
char *encoding_type;
char *csv_encoding_field_separator;
char *csv_encoding_row_separator;
char *csv_encoding_escape_character;
char *csv_encoding_report_format;
char *csv_encoding_row_time_stamp;
char *json_encoding_report_format;
char *json_encoding_report_time_stamp;
char *http_url;
char *http_username;
char *http_password;
char *http_compression;
char *http_method;
char *http_ssl_capath;
char *new_report;
time_t time_reference;
time_t next_retry;
time_t next_period;
bool http_persist_across_reboot;
bool http_insecure_enable;
bool enable;
bool http_use_date_header;
bool http_retry_enable;
struct profile_parameter *profile_parameter;
struct profile_http_request_uri_parameter *profile_http_uri_parameter;
struct list_head *failed_reports;
} profile;
typedef struct bulkdata {
struct device_id device_id;
struct profile *profile;
int log_level;
int amd_version;
unsigned int instance_mode;
} bulkdata;
int bulkdata_config_init(struct bulkdata *bulkdata);
int bulkdata_config_fini(struct bulkdata *bulkdata);
#ifndef FREE
#define FREE(x) do { if(x) {free(x); x = NULL;} } while (0)
#endif
#endif //__CONFIG_H

1294
bulkdata/src/datamodel.c Normal file

File diff suppressed because it is too large Load Diff

29
bulkdata/src/datamodel.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _BULKDATA_H_
#define _BULKDATA_H_
#include <libbbf_api/dmcommon.h>
extern DMOBJ tDeviceBulkDataObj[];
extern DMOBJ tBulkDataObj[];
extern DMLEAF tBulkDataParams[];
extern DMOBJ tBulkDataProfileObj[];
extern DMLEAF tBulkDataProfileParams[];
extern DMLEAF tBulkDataProfileParameterParams[];
extern DMLEAF tBulkDataProfileCSVEncodingParams[];
extern DMLEAF tBulkDataProfileJSONEncodingParams[];
extern DMOBJ tBulkDataProfileHTTPObj[];
extern DMLEAF tBulkDataProfileHTTPParams[];
extern DMLEAF tBulkDataProfileHTTPRequestURIParameterParams[];
#endif //__BULKDATA_H_

196
bulkdata/src/http.c Normal file
View File

@@ -0,0 +1,196 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Omar Kallel <omar.kallel@pivasoftware.com>
*/
#include "http.h"
static struct http_client http_c;
static CURL *curl;
int http_client_init(struct profile *profile)
{
char *url = create_request_url(profile);
if(url) {
asprintf(&http_c.url, "%s", url);
free(url);
}
bulkdata_log(SINFO, "ACS url: %s", http_c.url);
curl_global_init(CURL_GLOBAL_SSL);
curl = curl_easy_init();
if (!curl) return -1;
return 0;
}
void http_client_exit(void)
{
FREE(http_c.url);
if (http_c.header_list) {
curl_slist_free_all(http_c.header_list);
http_c.header_list = NULL;
}
curl_easy_cleanup(curl);
curl_global_cleanup();
}
static size_t http_get_response(void *buffer, size_t size, size_t rxed, char **msg_in)
{
char *c;
if (asprintf(&c, "%s%.*s", *msg_in, size * rxed, (char *)buffer) == -1) {
FREE(*msg_in);
return -1;
}
free(*msg_in);
*msg_in = c;
return size * rxed;
}
int http_send_message(struct profile *profile, char *msg_out, int msg_out_len, char **msg_in)
{
CURLcode res;
long http_code = 0;
char errbuf[CURL_ERROR_SIZE];
http_c.header_list = NULL;
http_c.header_list = curl_slist_append(http_c.header_list, "User-Agent: iopsys-bulkdata");
if (!http_c.header_list) return -1;
if (profile->http_use_date_header) {
if (bulkdata_get_time() != NULL) {
http_c.header_list = curl_slist_append(http_c.header_list, bulkdata_get_time());
if (!http_c.header_list) return -1;
}
}
if (strcmp(profile->encoding_type, "json") == 0) {
http_c.header_list = curl_slist_append(http_c.header_list, "Content-Type: application/json; charset=\"utf-8\"");
if (!http_c.header_list) return -1;
if(strcmp (profile->json_encoding_report_format, "objecthierarchy") == 0) {
http_c.header_list = curl_slist_append(http_c.header_list, "BBF-Report-Format: \"ObjectHierarchy\"");
if (!http_c.header_list) return -1;
} else if(strcmp(profile->json_encoding_report_format, "namevaluepair") == 0) {
http_c.header_list = curl_slist_append(http_c.header_list, "BBF-Report-Format: \"NameValuePair\"");
if (!http_c.header_list) return -1;
}
} else if(strcmp(profile->encoding_type, "csv") == 0) {
http_c.header_list = curl_slist_append(http_c.header_list, "Content-Type: text/csv; charset=\"utf-8\"");
if (!http_c.header_list) return -1;
if(strcmp (profile->csv_encoding_report_format, "row") == 0) {
http_c.header_list = curl_slist_append(http_c.header_list, "BBF-Report-Format: \"ParameterPerRow\"");
if (!http_c.header_list) return -1;
} else if(strcmp (profile->csv_encoding_report_format, "column") == 0) {
http_c.header_list = curl_slist_append(http_c.header_list, "BBF-Report-Format: \"ParameterPerColumn\"");
if (!http_c.header_list) return -1;
}
}
curl_easy_setopt(curl, CURLOPT_URL, http_c.url);
curl_easy_setopt(curl, CURLOPT_USERNAME, profile->http_username);
curl_easy_setopt(curl, CURLOPT_PASSWORD, profile->http_password);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_TIMEOUT);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, HTTP_TIMEOUT);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
if(strcasecmp(profile->http_compression, "gzip") == 0) {
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip");
http_c.header_list = curl_slist_append(http_c.header_list, "Content-Encoding: gzip");
} else if(strcasecmp(profile->http_compression, "compress") == 0) {
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "compress");
http_c.header_list = curl_slist_append(http_c.header_list, "Content-Encoding: compress");
} else if(strcasecmp(profile->http_compression, "deflate") == 0) {
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate");
http_c.header_list = curl_slist_append(http_c.header_list, "Content-Encoding: deflate");
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_c.header_list);
if(strcasecmp(profile->http_method, "put") == 0)
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg_out);
if (msg_out)
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) msg_out_len);
else
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_response);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, msg_in);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
if (profile->http_ssl_capath)
curl_easy_setopt(curl, CURLOPT_CAPATH, profile->http_ssl_capath);
if (profile->http_insecure_enable) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
}
*msg_in = (char *) calloc (1, sizeof(char));
res = curl_easy_perform(curl);
if(res != CURLE_OK) {
size_t len = strlen(errbuf);
if(len) {
if (errbuf[len - 1] == '\n') errbuf[len - 1] = '\0';
bulkdata_log(SCRIT, "libcurl: (%d) %s", res, errbuf);
} else {
bulkdata_log(SCRIT, "libcurl: (%d) %s", res, curl_easy_strerror(res));
}
}
if (!strlen(*msg_in))
FREE(*msg_in);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if(http_code == 200)
bulkdata_log(SINFO, "Receive HTTP 200 OK from Bulkdata Collector");
else if(http_code == 401)
bulkdata_log(SINFO, "Receive HTTP 401 Unauthorized from Bulkdata Collector");
else if(http_code == 204)
bulkdata_log(SINFO, "Receive HTTP 204 No Content from Bulkdata Collector");
else
bulkdata_log(SINFO, "Receive HTTP %d from Bulkdata Collector", http_code);
if(http_code == 415)
{
strcpy(profile->http_compression, "None");
goto error;
}
if (http_code != 200 && http_code != 204)
goto error;
curl_easy_reset(curl);
if (http_c.header_list) {
curl_slist_free_all(http_c.header_list);
http_c.header_list = NULL;
}
if (res) goto error;
return http_code;
error:
FREE(*msg_in);
if (http_c.header_list) {
curl_slist_free_all(http_c.header_list);
http_c.header_list = NULL;
}
return -1;
}

37
bulkdata/src/http.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#ifndef __HTTP_H
#define __HTTP_H
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <curl/curl.h>
#include "config.h"
#include "log.h"
#include "times.h"
#include "common.h"
#define HTTP_TIMEOUT 30
struct http_client
{
struct curl_slist *header_list;
char *url;
};
int http_client_init(struct profile *profile);
void http_client_exit(void);
int http_send_message(struct profile *profile, char *msg_out, int msg_out_len, char **msg_in);
#endif //__HTTP_H

57
bulkdata/src/log.c Normal file
View File

@@ -0,0 +1,57 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <syslog.h>
#include <time.h>
#include "bulkdata.h"
#include "config.h"
#include "log.h"
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 bulkdata_log(int priority, const char *format, ...)
{
va_list vl;
if (priority <= bulkdata_main.log_level) {
time_t t = time(NULL);
struct tm tm = *localtime(&t);
va_start(vl, format);
printf("%d-%02d-%02d %02d:%02d:%02d [bulkdata] %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");
openlog("bulkdata", 0, LOG_DAEMON);
va_start(vl, format);
vsyslog(log_syslogmap[priority], format, vl);
va_end(vl);
closelog();
}
}

28
bulkdata/src/log.h Normal file
View File

@@ -0,0 +1,28 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#ifndef __LOG_H
#define __LOG_H
#define DEFAULT_LOGLEVEL SINFO
enum bulkdata_log_level_enum {
SCRIT,
SWARNING,
SNOTICE,
SINFO,
SDEBUG,
__MAX_SLOG
};
void bulkdata_log(int priority, const char *format, ...);
#endif //__LOG_H

336
bulkdata/src/report.c Normal file
View File

@@ -0,0 +1,336 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*
*/
#include "report.h"
static void add_new_json_obj(json_object *json_obj, char *name, char *data, char *type)
{
json_object *jobj;
if(strstr(type, "unsignedInt") || strstr(type, "int") || strstr(type, "long"))
jobj = json_object_new_int64(atoi(data));
else if(strstr(type, "bool"))
jobj = json_object_new_boolean(atoi(data));
else
jobj = json_object_new_string(data);
json_object_object_add(json_obj, name, jobj);
}
static void create_json_bulkdata_report_object_hierarchy(struct profile *profile, char **report)
{
struct json_object *json_obj, *json_obj1, *json_obj2;
struct resultsnode *p;
int i, j, profile_param_number = profile->profile_parameter_number;
char *param_name, *result, *pch, *pchr, *collection_time = NULL;
char buf[1024] = {0};
json_obj = json_object_new_object();
get_time_stamp(profile->json_encoding_report_time_stamp, &collection_time);
if(collection_time) {
if(strcmp(profile->json_encoding_report_time_stamp, "iso8601") == 0)
json_object_object_add(json_obj, "CollectionTime", json_object_new_string(collection_time));
else
json_object_object_add(json_obj, "CollectionTime", json_object_new_int64(atoi(collection_time)));
free(collection_time);
}
json_obj2 = json_obj;
for (i = 0; i < profile_param_number; i++) {
LIST_HEAD(results_list);
bulkdata_get_value_results(profile->profile_parameter[i].reference, &results_list);
list_for_each_entry(p, &results_list, list) {
char *argv[128] = {0};
j = 0;
param_name = get_bulkdata_profile_parameter_name(profile->profile_parameter[i].reference, profile->profile_parameter[i].name, p->name);
strcpy(buf, param_name);
for (pch = strtok_r(buf, ".", &pchr); pch != NULL; pch = strtok_r(NULL, ".", &pchr)) {
argv[j] = pch;
json_obj1 = (json_object *)dmjson_select_obj(json_obj, argv);
if (json_obj1)
json_obj2 = json_obj1;
else {
if (pchr != NULL && *pchr != '\0') {
json_object *new_obj = json_object_new_object();
json_object_object_add(json_obj2, pch, new_obj);
json_obj2 = new_obj;
}
else
add_new_json_obj(json_obj2, pch, p->data, p->type);
}
j++;
}
}
bulkdata_free_data_from_list(&results_list);
FREE(param_name);
}
result = (char *)json_object_to_json_string_ext(json_obj, JSON_C_TO_STRING_PRETTY);
*report = strdup(result);
json_object_put(json_obj);
}
static void create_json_bulkdata_report_name_value_pair(struct profile *profile, char **report)
{
struct json_object *json_obj;
struct resultsnode *p;
char *param_name, *result, *collection_time = NULL;
int i = 0, profile_param_number = profile->profile_parameter_number;
json_obj = json_object_new_object();
get_time_stamp(profile->json_encoding_report_time_stamp, &collection_time);
if(collection_time) {
if(strcmp(profile->json_encoding_report_time_stamp, "iso8601") == 0)
json_object_object_add(json_obj, "CollectionTime", json_object_new_string(collection_time));
else
json_object_object_add(json_obj, "CollectionTime", json_object_new_int64(atoi(collection_time)));
free(collection_time);
}
for (i = 0; i < profile_param_number; i++) {
LIST_HEAD(results_list);
bulkdata_get_value_results(profile->profile_parameter[i].reference, &results_list);
list_for_each_entry(p, &results_list, list) {
param_name = get_bulkdata_profile_parameter_name(profile->profile_parameter[i].reference, profile->profile_parameter[i].name, p->name);
add_new_json_obj(json_obj, param_name, p->data, p->type);
FREE(param_name);
}
bulkdata_free_data_from_list(&results_list);
}
result = (char *)json_object_to_json_string_ext(json_obj, JSON_C_TO_STRING_PRETTY);
*report = strdup(result);
json_object_put(json_obj);
}
static void add_failed_reports_to_report_json(struct profile *profile, char *new_report, char **report, int isnext)
{
json_object *json_obj, *json_array, *json_string;
struct failed_reports *retreport = NULL;
char *msgout = NULL;
int j = 0;
json_obj = json_object_new_object();
json_array = json_object_new_array();
json_object_object_add(json_obj,"Report", json_array);
if(list_empty(profile->failed_reports))
goto new_report;
list_for_each_entry(retreport, profile->failed_reports, list) {
if(!j && isnext) {
j = 1;
continue;
}
json_string = json_tokener_parse(retreport->freport);
json_object_array_add(json_array, json_string);
}
new_report :
if(new_report) {
json_string = json_tokener_parse(new_report);
json_object_array_add(json_array, json_string);
}
msgout = (char *)json_object_to_json_string_ext(json_obj, JSON_C_TO_STRING_PRETTY);
*report = strdup(msgout);
json_object_put(json_obj);
}
static void create_report_json(char *new_report, char **report)
{
json_object *json_obj, *json_array, *json_string;
char *msgout = NULL;
json_obj = json_object_new_object();
json_array = json_object_new_array();
json_object_object_add(json_obj,"Report", json_array);
if(new_report) {
json_string = json_tokener_parse(new_report);
json_object_array_add(json_array, json_string);
}
msgout = (char *)json_object_to_json_string_ext(json_obj, JSON_C_TO_STRING_PRETTY);
*report = strdup(msgout);
json_object_put(json_obj);
}
int create_json_bulkdata_report(struct profile *profile, char **report)
{
/*
* create json msg of current report
* parse failed reports list and add it to the report
* then add new report to the report
*/
char *msgout;
profile->new_report = NULL;
if(strcmp(profile->json_encoding_report_format, "objecthierarchy") == 0) {
create_json_bulkdata_report_object_hierarchy(profile, &msgout);
} else if(strcmp(profile->json_encoding_report_format, "namevaluepair") == 0) {
create_json_bulkdata_report_name_value_pair(profile, &msgout);
}
if(profile->nbre_of_retained_failed_reports != 0) {
if(profile->nbre_failed_reports >= profile->nbre_of_retained_failed_reports && profile->nbre_of_retained_failed_reports > 0)
add_failed_reports_to_report_json(profile, msgout, report, 1);
else
add_failed_reports_to_report_json(profile, msgout, report, 0);
} else {
create_report_json(msgout, report);
}
append_string_to_string(msgout, &profile->new_report);
FREE(msgout);
return 0;
}
int create_csv_bulkdata_report(struct profile *profile, char **report)
{
/*
* create csv msg of current report
* parse failed reports list and add it to the report
*/
int i;
struct resultsnode *p;
char *str1 = NULL, *str2 = NULL, *str = NULL, *paramprofilename, *timestamp = NULL, *type = NULL, rowseparator = '\0', separator = '\0';
if(strcmp(profile->csv_encoding_row_separator, "&#10;") == 0)
rowseparator = '\n';
else if(strcmp(profile->csv_encoding_row_separator, "&#13;") == 0)
rowseparator = '\r';
if(profile->csv_encoding_field_separator)
separator = profile->csv_encoding_field_separator[0];
get_time_stamp(profile->csv_encoding_row_time_stamp, &timestamp);
/*
* Create header ReportTimestamp,ParameterName,ParameterValue,ParameterType in case of ParameterPerRow
*/
if(strcmp(profile->csv_encoding_report_format, "row") == 0) {
if(timestamp == NULL)
asprintf(&str, "ParameterName%cParameterValue%cParameterType%c", separator, separator, rowseparator);
else
asprintf(&str, "ReportTimestamp%cParameterName%cParameterValue%cParameterType%c", separator, separator, separator, rowseparator);
append_string_to_string(str, report);
FREE(str);
if(profile->nbre_of_retained_failed_reports != 0) {
if(profile->nbre_failed_reports >= profile->nbre_of_retained_failed_reports && profile->nbre_of_retained_failed_reports > 0)
add_failed_reports_to_report_csv(profile, report, 1);
else
add_failed_reports_to_report_csv(profile, report, 0);
}
}
if(strcmp(profile->csv_encoding_report_format, "column") == 0 && timestamp != NULL) {
if(profile->nbre_of_retained_failed_reports != 0) {
if(profile->nbre_failed_reports >= profile->nbre_of_retained_failed_reports && profile->nbre_of_retained_failed_reports > 0)
add_failed_reports_to_report_csv(profile, report, 1);
else
add_failed_reports_to_report_csv(profile, report, 0);
}
append_string_to_string("ReportTimestamp", &str1);
append_string_to_string(timestamp, &str2);
}
/*
* Add New reports
*/
profile->new_report = NULL;
for(i = 0; i < profile->profile_parameter_number; i++) {
LIST_HEAD(results_list);
bulkdata_get_value_results(profile->profile_parameter[i].reference, &results_list);
list_for_each_entry(p, &results_list, list) {
paramprofilename = get_bulkdata_profile_parameter_name(profile->profile_parameter[i].reference, profile->profile_parameter[i].name, p->name);
if(strcmp(profile->csv_encoding_report_format, "row") == 0) {
type = strstr(p->type, ":");
if(timestamp == NULL)
asprintf(&str, "%s%c%s%c%s%c", paramprofilename, separator, p->data, separator, type+1, rowseparator);
else
asprintf(&str, "%s%c%s%c%s%c%s%c", timestamp, separator, paramprofilename, separator, p->data, separator, type+1, rowseparator);
append_string_to_string(str, report);
append_string_to_string(str, &profile->new_report);
FREE(str);
} else if(strcmp(profile->csv_encoding_report_format, "column") == 0) {
if(str1 == NULL || strlen(str1) <= 0)
asprintf(&str, "%s", paramprofilename);
else
asprintf(&str, "%c%s", separator, paramprofilename);
append_string_to_string(str, &str1);
FREE(str);
if(str2 == NULL || strlen(str2) <= 0)
asprintf(&str, "%s", p->data);
else
asprintf(&str, "%c%s", separator, p->data);
append_string_to_string(str, &str2);
FREE(str);
}
FREE(paramprofilename);
}
bulkdata_free_data_from_list(&results_list);
}
if(strcmp(profile->csv_encoding_report_format, "column") == 0) {
asprintf(&str, "%c", rowseparator);
append_string_to_string(str, &str1);
append_string_to_string(str, &str2);
append_string_to_string(str1, report);
append_string_to_string(str2, report);
append_string_to_string(str1, &profile->new_report);
append_string_to_string(str2, &profile->new_report);
}
FREE(str);
FREE(str1);
FREE(str2);
FREE(timestamp);
return 0;
}
static void create_json_failed_report(struct profile *profile, char **report)
{
add_failed_reports_to_report_json(profile, NULL, report, 0);
}
static void create_csv_failed_report(struct profile *profile, char **report)
{
char rowseparator = '\0', separator = '\0', *timestamp = NULL;
if(strcmp(profile->csv_encoding_row_separator, "&#10;") == 0) {
rowseparator = '\n';
} else if(strcmp(profile->csv_encoding_row_separator, "&#13;") == 0) {
rowseparator = '\r';
}
if(profile->csv_encoding_field_separator)
separator = profile->csv_encoding_field_separator[0];
get_time_stamp(profile->csv_encoding_row_time_stamp, &timestamp);
if(strcmp(profile->csv_encoding_report_format, "row") == 0) {
if(timestamp == NULL)
asprintf(report, "ParameterName%cParameterValue%cParameterType%c", separator, separator, rowseparator);
else
asprintf(report, "ReportTimestamp%cParameterName%cParameterValue%cParameterType%c", separator, separator, separator, rowseparator);
}
add_failed_reports_to_report_csv(profile, report, 0);
}
void create_encoding_bulkdata_report(struct profile *profile, char **report)
{
if(strcasecmp(profile->encoding_type, "json") == 0) {
create_json_bulkdata_report(profile, report);
} else if(strcasecmp(profile->encoding_type, "csv") == 0) {
create_csv_bulkdata_report(profile, report);
}
}
void create_failed_report(struct profile *profile, char **report)
{
if(strcasecmp(profile->encoding_type, "json") == 0) {
create_json_failed_report(profile, report);
} else if(strcasecmp(profile->encoding_type, "csv") == 0) {
create_csv_failed_report(profile, report);
}
}

24
bulkdata/src/report.h Normal file
View File

@@ -0,0 +1,24 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*
*/
#ifndef __REPORT_H_
#define __REPORT_H_
#include <json-c/json.h>
#include "common.h"
#include "times.h"
#include "config.h"
void create_encoding_bulkdata_report(struct profile *profile, char **report);
void create_failed_report(struct profile *profile, char **report);
#endif /* __REPORT_H_ */

62
bulkdata/src/times.c Normal file
View File

@@ -0,0 +1,62 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "times.h"
const char *bulkdata_get_time(void)
{
static char local_time[64];
time_t t_time = time(NULL);
struct tm *t_tm = localtime(&t_time);
if (t_tm == NULL)
return NULL;
if (strftime(local_time, sizeof(local_time),"Date: %a, %d %b %Y %X%z GMT", t_tm) == 0)
return NULL;
return local_time;
}
void get_time_stamp(const char *format, char **timestamp)
{
time_t now = time(NULL);
if (strcmp(format, "unix") == 0) {
asprintf(timestamp, "%ld", now);
} else if (strcmp(format, "iso8601") == 0) {
char buf[32] = {0};
struct tm *ts = localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%Z", ts);
asprintf(timestamp, "%s", buf);
} else
timestamp = NULL;
}
unsigned int get_next_period(time_t time_reference, int reporting_interval)
{
unsigned int next_period;
time_t now = time(NULL);
if (now > time_reference)
next_period = reporting_interval - ((now - time_reference) % reporting_interval);
else
next_period = (time_reference - now) % reporting_interval;
if (next_period == 0)
next_period = reporting_interval;
return next_period;
}

19
bulkdata/src/times.h Normal file
View File

@@ -0,0 +1,19 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
*/
#ifndef __TIMES_H
#define __TIMES_H
const char *bulkdata_get_time(void);
void get_time_stamp(const char *format, char **timestamp);
unsigned int get_next_period(time_t time_reference, int reporting_interval);
#endif /* __TIMES_H */

View File

@@ -7,13 +7,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=easy-soc-libs
PKG_VERSION:=4.8.6
PKG_VERSION:=5.3.15
PKG_RELEASE:=1
LOCAL_DEV=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=7ee57451ac6ed25fd2c1c38e58a508b0362245a7
PKG_SOURCE_VERSION:=a2289131c5d1f602568a2e8cac1295442504827f
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/easy-soc-libs.git
PKG_MAINTAINER:=Anjan Chanda <anjan.chanda@iopsys.eu>
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(PKG_SOURCE_VERSION).tar.xz
@@ -136,6 +136,7 @@ define Build/InstallDev/libeasy
$(CP) $(PKG_BUILD_DIR)/libeasy/easy.h $(1)/usr/include/easy/
$(CP) $(PKG_BUILD_DIR)/libeasy/event.h $(1)/usr/include/easy/
$(CP) $(PKG_BUILD_DIR)/libeasy/utils.h $(1)/usr/include/easy/
$(CP) $(PKG_BUILD_DIR)/libeasy/debug.h $(1)/usr/include/easy/
$(CP) $(PKG_BUILD_DIR)/libeasy/libeasy*.so* $(1)/usr/lib/
endef

View File

@@ -129,6 +129,8 @@ static int canyon_led_probe(struct platform_device *pdev)
if (ret < 0) {
dev_warn(&pdev->dev, "Could not read led-count property\n");
leds->led_count = SK9822_DEFAULT_NUM_LEDS;
} else {
printk(KERN_INFO "Got led count: %u\n", leds->led_count);
}
leds->led_colors = devm_kzalloc(&pdev->dev,
@@ -140,7 +142,7 @@ static int canyon_led_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, leds);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 16, 0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
leds->clock_gpio = gpiod_get_index(&pdev->dev, "led", 0);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
leds->clock_gpio = gpiod_get_index(&pdev->dev, "led", 0, GPIOD_OUT_HIGH);
@@ -148,6 +150,12 @@ static int canyon_led_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Kernel version Not supported\n");
exit(1);
#endif
if (IS_ERR(leds->clock_gpio)) {
dev_err(&pdev->dev, "Failed to acquire clock GPIO %ld\n",
PTR_ERR(leds->clock_gpio));
leds->clock_gpio = NULL;
return PTR_ERR(leds->clock_gpio);
}
gpiod_direction_output(leds->clock_gpio, 1);
if (IS_ERR(leds->clock_gpio)) {
@@ -160,7 +168,7 @@ static int canyon_led_probe(struct platform_device *pdev)
gpiod_set_value(leds->clock_gpio, 0);
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 16, 0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
leds->data_gpio = gpiod_get_index(&pdev->dev, "led", 1);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
leds->data_gpio = gpiod_get_index(&pdev->dev, "led", 1, GPIOD_OUT_HIGH);
@@ -168,6 +176,12 @@ static int canyon_led_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Kernel version Not supported\n");
exit(1);
#endif
if (IS_ERR(leds->data_gpio)) {
dev_err(&pdev->dev, "Failed to acquire data GPIO %ld\n",
PTR_ERR(leds->data_gpio));
leds->data_gpio = NULL;
return PTR_ERR(leds->data_gpio);
}
gpiod_direction_output(leds->data_gpio, 1);
if (IS_ERR(leds->data_gpio)) {

View File

@@ -1,4 +1,4 @@
if PACKAGE_icwmp-curl || PACKAGE_icwmp-zstream
if PACKAGE_icwmp
config CWMP_SCRIPTS_FULL
bool "Install all icwmp scripts"
@@ -22,6 +22,6 @@ config CWMP_DEBUG
config CWMP_DEVEL_DEBUG
bool "Compile with development debug options"
default n
endif

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 iopsys Software Solutions AB
# Copyright (C) 2020 iopsys Software Solutions AB
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
@@ -8,11 +8,11 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=icwmp
PKG_VERSION:=4.0-2020-07-07
PKG_VERSION:=5.0-2020-10-02
PKG_FIXUP:=autoreconf
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/icwmp.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=03a438d926247ac3eff5df1c5eeea3d6d2babd2b
PKG_SOURCE_VERSION:=f46ec43092f879a82923d03e7cc104ccc6e335ad
PKG_RELEASE=$(PKG_SOURCE_VERSION)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
@@ -26,80 +26,41 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_CWMP_DEBUG \
CONFIG_CWMP_DEVEL_DEBUG
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
CWMP_REVISION=$(shell svnversion ./src/ -n|cut -f2 -d:)
include $(INCLUDE_DIR)/package.mk
define Package/icwmp_stun
SECTION:=utils
CATEGORY:=Utilities
TITLE:=TR-069 stun Client
DEPENDS:=+PACKAGE_icwmp_stun:libubus +PACKAGE_icwmp_stun:libuci +PACKAGE_icwmp_stun:libubox +PACKAGE_icwmp_stun:libjson-c +PACKAGE_icwmp_stun:libopenssl +PACKAGE_icwmp_stun:libblobmsg-json
endef
define Package/icwmp_xmpp
SECTION:=utils
CATEGORY:=Utilities
TITLE:=TR-069 xmpp feature
DEPENDS:=+PACKAGE_icwmp_xmpp:libuci +PACKAGE_icwmp_xmpp:libubox +PACKAGE_icwmp_xmpp:libexpat +PACKAGE_icwmp_xmpp:libstrophe
endef
define Package/icwmp_twamp
SECTION:=utils
CATEGORY:=Utilities
TITLE:=TR-069 twamp feature
DEPENDS:=+PACKAGE_icwmp_twamp:libuci
endef
define Package/icwmp_udpechoserver
SECTION:=utils
CATEGORY:=Utilities
TITLE:=TR-069 udpechoserver feature
DEPENDS:=+PACKAGE_icwmp_udpechoserver:libuci
endef
define Package/icwmp_bulkdata
SECTION:=utils
CATEGORY:=Utilities
TITLE:=TR-069 BulkData Collection
DEPENDS:=+PACKAGE_icwmp_bulkdata:libubus +PACKAGE_icwmp_bulkdata:libuci +PACKAGE_icwmp_bulkdata:libubox +PACKAGE_icwmp_bulkdata:libjson-c +PACKAGE_icwmp_bulkdata:libcurl +PACKAGE_icwmp_bulkdata:curl +PACKAGE_icwmp_bulkdata:libblobmsg-json +PACKAGE_icwmp_bulkdata:libbbfdm
endef
define Package/icwmp-tr098
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=CWMP client for TR-098 Data Model
DEPENDS:=+PACKAGE_icwmp-tr098:libuci +PACKAGE_icwmp-tr098:libmicroxml +PACKAGE_icwmp-tr098:libubox +PACKAGE_icwmp-tr098:jshn +PACKAGE_icwmp-tr098:libubus +PACKAGE_icwmp-tr098:libblobmsg-json +PACKAGE_icwmp-tr098:libpthread +PACKAGE_icwmp-tr098:ubusd +PACKAGE_icwmp-tr098:shflags +PACKAGE_icwmp-tr098:getopt +PACKAGE_icwmp-tr098:zlib +PACKAGE_icwmp-tr098:libjson-c +PACKAGE_icwmp-tr098:libopenssl +PACKAGE_icwmp-tr098:curl +PACKAGE_icwmp-tr098:libcurl +PACKAGE_icwmp-tr098:libtr098
endef
define Package/icwmp/Default
define Package/icwmp-notifd
SECTION:=utils
CATEGORY:=Utilities
TITLE:=CWMP client
DEPENDS:=+libuci +libmicroxml +libubox +jshn +libubus +libblobmsg-json +libpthread +ubusd +shflags +getopt +zlib +libjson-c +libopenssl +curl +libbbfdm +libbbf_api
SUBMENU:=TRx69
TITLE:=CWMP Active Notifications Detect tool
DEPENDS:=+libubox +libuci +libbbfdm +libjson-c +libubus +libblobmsg-json
endef
define Package/icwmp/description
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=CWMP client
DEPENDS:=+libuci +libmicroxml +libubox +jshn +libubus +libblobmsg-json +libpthread +ubusd +shflags +getopt +zlib +libjson-c +libopenssl +curl +libcurl +libbbfdm +libbbf_api
endef
define Package/$(PKG_NAME)/description
A free client implementation of CWMP (TR-069) protocol
endef
define Package/icwmp-curl
$(call Package/icwmp/Default)
TITLE+= (using libcurl)
DEPENDS+= +PACKAGE_icwmp-curl:libcurl
VARIANT:=curl
endef
define Package/icwmp-zstream
$(call Package/icwmp/Default)
TITLE+= (using libzstream)
DEPENDS+= +PACKAGE_icwmp-zstream:libzstream
VARIANT:=zstream
endef
define Package/icwmp-curl/config
define Package/$(PKG_NAME)/config
source "$(SOURCE)/Config_cwmp.in"
endef
@@ -118,29 +79,9 @@ CONFIGURE_ARGS += \
--enable-icwmp_tr098
endif
ifeq ($(CONFIG_PACKAGE_icwmp_xmpp),y)
ifeq ($(CONFIG_PACKAGE_icwmp-notifd),y)
CONFIGURE_ARGS += \
--enable-icwmp_xmpp
endif
ifeq ($(CONFIG_PACKAGE_icwmp_stun),y)
CONFIGURE_ARGS += \
--enable-icwmp_stun
endif
ifeq ($(CONFIG_PACKAGE_icwmp_udpechoserver),y)
CONFIGURE_ARGS += \
--enable-icwmp_udpechoserver
endif
ifeq ($(CONFIG_PACKAGE_icwmp_twamp),y)
CONFIGURE_ARGS += \
--enable-icwmp_twamp
endif
ifeq ($(CONFIG_PACKAGE_icwmp_bulkdata),y)
CONFIGURE_ARGS += \
--enable-icwmp_bulkdata
--enable-icwmp_notifd
endif
ifneq ($(CWMP_REVISION)_,_)
@@ -159,17 +100,6 @@ CONFIGURE_ARGS += \
--with-uci-include-path=$(STAGING_DIR)/usr/include \
--with-libubox-include-path=$(STAGING_DIR)/usr/include \
--with-libubus-include-path=$(STAGING_DIR)/usr/include
ifeq ($(BUILD_VARIANT),zstream)
CONFIGURE_ARGS += \
--enable-http=zstream \
--with-zstream-include-path=$(STAGING_DIR)/usr/include
endif
ifeq ($(BUILD_VARIANT),curl)
CONFIGURE_ARGS += \
--enable-http=curl
endif
ifeq ($(CONFIG_CWMP_ACS_MULTI),y)
CONFIGURE_ARGS += \
@@ -191,17 +121,10 @@ CONFIGURE_ARGS += \
--enable-devel
endif
define Package/icwmp-$(BUILD_VARIANT)/install
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/icwmpd
$(INSTALL_DIR) $(1)/usr/sbin
$(CP) $(PKG_BUILD_DIR)/bin/icwmpd $(1)/usr/sbin
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/config/cwmp $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/config/firewall.cwmp $(1)/etc/firewall.cwmp
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) $(PKG_BUILD_DIR)/init/icwmpd.init $(1)/etc/init.d/icwmpd
$(INSTALL_BIN) $(PKG_BUILD_DIR)/uci-defaults/* $(1)/etc/uci-defaults/
ifeq ($(CONFIG_CWMP_SCRIPTS_FULL),y)
$(INSTALL_DIR) $(1)/usr/share/icwmp
$(CP) $(PKG_BUILD_DIR)/scripts/defaults $(1)/usr/share/icwmp
@@ -217,55 +140,13 @@ define Package/icwmp-tr098/install
$(CP) $(PKG_BUILD_DIR)/bin/icwmp_tr098d $(1)/usr/sbin
endef
define Package/icwmp_stun/install
define Package/icwmp-notifd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/icwmp_stund $(1)/usr/sbin/icwmp_stund
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/init/icwmp_stund $(1)/etc/init.d/icwmp_stund
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/config/cwmp_stun $(1)/etc/config
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/icwmp_notifd $(1)/usr/sbin/icwmp_notifd
endef
define Package/icwmp_xmpp/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/icwmp_xmppd $(1)/usr/sbin/icwmp_xmppd
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/init/icwmp_xmppd $(1)/etc/init.d/icwmp_xmppd
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/config/cwmp_xmpp $(1)/etc/config
$(CP) ./xmpp-files/* $(1)/
endef
define Package/icwmp_udpechoserver/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/icwmp_udpechoserverd $(1)/usr/sbin/icwmp_udpechoserverd
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/init/icwmp_udpechoserverd $(1)/etc/init.d/icwmp_udpechoserverd
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/config/cwmp_udpechoserver $(1)/etc/config
endef
define Package/icwmp_twamp/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/icwmp_twampd $(1)/usr/sbin/icwmp_twampd
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/init/icwmp_twampd $(1)/etc/init.d/icwmp_twampd
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/config/cwmp_twamp $(1)/etc/config
endef
define Package/icwmp_bulkdata/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/icwmp_bulkdatad $(1)/usr/sbin/icwmp_bulkdatad
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/init/icwmp_bulkdatad $(1)/etc/init.d/icwmp_bulkdatad
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/config/cwmp_bulkdata $(1)/etc/config
endef
define Package/icwmp-$(BUILD_VARIANT)/postinst
define Package/$(PKG_NAME)/postinst
#!/bin/sh
echo "$(CWMP_BKP_FILE)" >> $${IPKG_INSTROOT}/etc/sysupgrade.conf
if [ -z "$${IPKG_INSTROOT}" ]; then
echo "Enabling rc.d symlink for icwmpd"
/etc/init.d/icwmpd enable
@@ -273,7 +154,7 @@ define Package/icwmp-$(BUILD_VARIANT)/postinst
exit 0
endef
define Package/icwmp-$(BUILD_VARIANT)/prerm
define Package/$(PKG_NAME)/prerm
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
echo "Disabling rc.d symlink for icwmpd"
@@ -282,11 +163,6 @@ define Package/icwmp-$(BUILD_VARIANT)/prerm
exit 0
endef
$(eval $(call BuildPackage,icwmp-curl))
$(eval $(call BuildPackage,icwmp_stun))
$(eval $(call BuildPackage,icwmp_xmpp))
$(eval $(call BuildPackage,icwmp_udpechoserver))
$(eval $(call BuildPackage,icwmp_twamp))
$(eval $(call BuildPackage,icwmp_bulkdata))
$(eval $(call BuildPackage,$(PKG_NAME)))
$(eval $(call BuildPackage,icwmp-tr098))
#$(eval $(call BuildPackage,icwmp-zstream))
$(eval $(call BuildPackage,icwmp-notifd))

View File

@@ -0,0 +1,46 @@
config acs 'acs'
option url ''
option userid '' #$OUI-$SER
option passwd 'iopsys'
option periodic_inform_enable 'true'
option periodic_inform_interval '1800'
option periodic_inform_time '0'
option ParameterKey ''
option dhcp_discovery 'enable'
# compression possible configs: GZIP, Deflate, Disabled
option compression 'Disabled'
#­ possible configs interval :[1:65535]
option retry_min_wait_interval '5'
#­ possible configs interval :[1000:65535]
option retry_interval_multiplier '2000'
option https_ssl_capath ''
option ipv6_enable '0'
config cpe 'cpe'
option interface 'eth0.1'
option default_wan_interface 'wan'
option log_to_console 'disable'
option log_to_file 'enable'
# log_severity: INFO (Default)
# log_severity possible configs: EMERG, ALERT, CRITIC ,ERROR, WARNING, NOTICE, INFO, DEBUG
option log_severity 'INFO'
option log_file_name '/var/log/icwmpd.log'
option log_max_size '102400'
option userid '' #$OUI-$SER
option passwd 'iopsys'
option port '7547'
option ubus_socket '/var/run/ubus.sock'
option provisioning_code ''
option amd_version '5'
# compression possible configs: InstanceNumber, InstanceAlias
option instance_mode 'InstanceNumber'
option session_timeout '60'
option notification '1'
option datamodel 'tr181'
option exec_download '0'
option polling_period '5'
config lwn 'lwn'
option enable '1'
option hostname ''
option port '0'

View File

@@ -0,0 +1,21 @@
#created by the icwmp package
zone_name=""
port=""
if [ "$zone_name" = "" ]; then
exit 0
elif [ "$zone_name" = "icwmp" ]; then
iptables -nL zone_icwmp_input 2> /dev/null
if [ $? != 0 ]; then
iptables -N zone_icwmp_input
iptables -t filter -A INPUT -j zone_icwmp_input
iptables -I zone_icwmp_input -p tcp --dport $port -j REJECT
else
iptables -F zone_icwmp_input
iptables -I zone_icwmp_input -p tcp --dport $port -j REJECT
fi
else
iptables -F zone_icwmp_input 2> /dev/null
iptables -t filter -D INPUT -j zone_icwmp_input 2> /dev/null
iptables -X zone_icwmp_input 2> /dev/null
fi
#iptables -I FW_ZONE -p tcp -s ACS_ADDRESS --dport PORT -j ACCEPT --comment "Open ACS port"

229
icwmp/files/etc/init.d/icwmpd Executable file
View File

@@ -0,0 +1,229 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2015-2019 iopsys Software Solutions AB
. /lib/functions.sh
include /lib/network
. /usr/share/libubox/jshn.sh
START=99
STOP=10
USE_PROCD=1
PROG="/usr/sbin/icwmpd"
EXTRA_COMMANDS="notify"
EXTRA_HELP=" start [GetRPCMethods] Start icwmpd service and send GetRPCMethods"
validate_url() {
# SCHEMA_LIST: contain list of possible schemas that could be present in the acs url
# Example: SCHEMA_LIST="http https"
SCHEMA_LIST="http"
for schema in $SCHEMA_LIST; do
dest=`echo $1 | sed 's/$schema:\/\///g' | cut -f1 -d \/ | cut -f1 -d:`
if [ "_$dest" != "_" ]; then
return 0
fi
done
return 1
}
build_dmmap_instance() {
[ ! -e /etc/icwmpd/.icwmpd_backup_session.xml ] && /usr/sbin/icwmp get name "" 0 >/dev/null 2>&1
}
get_acs_url() {
local default_acs="http://10.10.1.6:8000/openacs/acs"
local acs_dhcp_discovery="$(uci -q get cwmp.acs.dhcp_discovery)"
local url="$(uci -q get cwmp.acs.url)"
local dhcp_url="$(uci -P /var/state -q get cwmp.acs.dhcp_url)"
if [ "$acs_dhcp_discovery" == "enable" -a -n "$dhcp_url" -o -z "$url" ]; then
url="$dhcp_url"
echo "ACS URL from DHCP server: $url"
[ -n "$url" ] && uci -P /var/state -q set cwmp.acs.url="$url" || url="$default_acs"
elif [ -n "$url" ];then
url="$(uci -q get cwmp.acs.url)"
echo "ACS URL from configuration: $url"
else
url="$default_acs"
echo "Using default ACS URL: $url"
[ -n "$url" ] && uci -P /var/state -q set cwmp.acs.url="$url"
fi
validate_url "$url"
if [ "$?" != "0" ];then
echo "Invalid ACS URL: $url"
exit 1
fi
}
enable_dhcp_option43() {
local wan=$1
local discovery=0
case $2 in
enable|1) discovery=1 ;;
esac
### Ask for DHCP Option 43 only if CWMP is enabled ###
local enabled
local newreqopts=
local baseopts=
local reqopts="$(uci -q get network.$wan.reqopts)"
local proto="$(uci -q get network.$wan.proto)"
local tropts="43"
local oldreqopts="$reqopts"
local ropt iopt
for ropt in $reqopts; do
case $ropt in
43) ;;
*) baseopts="$baseopts $ropt" ;;
esac
done
ropt=""
reqopts="$baseopts $tropts"
for ropt in $reqopts; do
case $ropt in
43) [ $discovery -eq 1 ] && newreqopts="$newreqopts $ropt" ;;
*) newreqopts="$newreqopts $ropt" ;;
esac
done
if [ $proto == "dhcp" ]; then
newreqopts="$(echo $newreqopts | tr ' ' '\n' | sort -n | tr '\n' ' ' | sed 's/^[ \t]*//;s/[ \t]*$//')"
oldreqopts="$(echo $oldreqopts | tr ' ' '\n' | sort -n | tr '\n' ' ' | sed 's/^[ \t]*//;s/[ \t]*$//')"
[ "$newreqopts" == "$oldreqopts" ] && return
uci -q set network.$wan.reqopts="$newreqopts"
uci commit network
ubus call network reload
fi
########################################################
}
wait_for_option43() {
local time=$1
local default_wan_interface dhcp_discovery url
config_get default_wan_interface cpe default_wan_interface "wan"
config_get dhcp_discovery acs dhcp_discovery "0"
config_get url acs url
enable_dhcp_option43 $default_wan_interface $dhcp_discovery
local tm=0
if [ "$dhcp_discovery" == "enable" -o "$dhcp_discovery" == "1" ]
then
echo "Waiting for discovery of ACS URL from dhcp server ..."
while [ $tm -le $time ]
do
acs_url=`uci -P /var/state -q get cwmp.acs.dhcp_url`
if [ "$acs_url" != "" ]
then
break
else
sleep 1
fi
tm=$((tm+1))
done
fi
}
wait_for_wifi() {
local time=$1
local tm=1
while [ ! -f /tmp/wifi.started ]; do
sleep 1
[ $tm -ge $time ] && break
tm=$((tm+1))
done
}
wait_for_resolvfile() {
local time=$1
local tm=1
local resolvfile="$(uci -q get dhcp.@dnsmasq[0].resolvfile)"
[ -n "$resolvfile" ] || return
while [ ! -f $resolvfile ]; do
sleep 1
[ $tm -ge $time ] && break
tm=$((tm+1))
done
}
wait_for_asterisk() {
local time=$1
local tm=1
while [ -z "$(pidof asterisk)" ]; do
sleep 1
[ $tm -ge $time ] && break
tm=$((tm+1))
done
}
set_wan_interface() {
local l3_device=""
local default_wan_interface=""
config_get default_wan_interface cpe default_wan_interface "wan"
json_load "$(ifstatus $default_wan_interface)"
json_get_var l3_device l3_device
if [ "$l3_device" != "" ];then
uci -q set cwmp.cpe.interface="$l3_device"
uci -q commit cwmp
fi
}
start_service() {
if [ ! -f /tmp/.icwmpd_boot ]; then
touch /etc/icwmpd/.icwmpd_boot
touch /tmp/.icwmpd_boot
else
[ -f /sbin/netifd ] && echo "Waiting for Network to be started ..." && ubus -t 5 wait_for network.interface
[ -f /etc/config/wireless ] && echo "Waiting for WiFi to be started ..." && wait_for_wifi 20
[ -f /usr/sbin/dnsmasq ] && echo "Waiting for DNS Proxy to be started ..." && ubus -t 5 wait_for dnsmasq
[ -f /etc/config/dhcp ] && echo "Waiting for DNS Server(s) ..." && wait_for_resolvfile 20
[ -f /usr/sbin/asterisk ] && echo "Waiting for Voice to be started ..." && wait_for_asterisk 5
config_load cwmp
build_dmmap_instance
set_wan_interface
wait_for_option43 20
get_acs_url
procd_open_instance
procd_set_param command "$PROG"
if [ "$1" = "GetRPCMethods" ];then
procd_append_param command -g
elif [ -f /etc/icwmpd/.icwmpd_boot ]; then
procd_append_param command -b
fi
procd_set_param respawn "3" "7" "0"
procd_close_instance
#procd_open_instance
#[ "$(uci -q get cwmp.cpe.notification)" == "1" ] && procd_append_param command "/usr/sbin/icwmp_notifd"
#procd_close_instance
fi
}
reload_service() {
stop
start
}
notify() {
ubus -t 1 call tr069 notify >/dev/null 2>&1 &
}
service_triggers() {
procd_add_config_trigger "config.change" "cwmp" /etc/init.d/icwmpd reload
if [ "$(uci -q get cwmp.cpe.notification)" == "1" ]; then
for conf in $(ls /etc/config/); do
procd_add_config_trigger "config.change" "$conf" /etc/init.d/icwmpd notify
done
fi
}

View File

@@ -1,4 +1,3 @@
# Copy defaults by the factory to the cwmp UCI user section.
@@ -15,10 +14,19 @@ mac=$(printf "%12.12X" $((0x$baseMac)))
# Get system serial number.
serial=$(db -q get hw.board.serial_number)
uci -q batch <<-EOF
set cwmp.acs.userid="${mac:0:6}-${serial}"
set cwmp.cpe.userid="${mac:0:6}-${serial}"
EOF
# Get userid values
acs_userid=$(uci -q get cwmp.acs.userid)
cpe_userid=$(uci -q get cwmp.cpe.userid)
# Only set if they are empty
if [ -z "$acs_userid" ]
then
uci -q set cwmp.acs.userid="${mac:0:6}-${serial}"
fi
if [ -z "$cpe_userid" ]
then
uci -q set cwmp.cpe.userid="${mac:0:6}-${serial}"
fi
# No need for commit here, it is done by uci_apply_defaults().

View File

@@ -0,0 +1,12 @@
#!/bin/sh
uci -q batch <<-EOT
delete firewall.cwmp
set firewall.cwmp=include
set firewall.cwmp.path=/etc/firewall.cwmp
set firewall.cwmp.reload=1
commit firewall
EOT
exit 0

View File

@@ -0,0 +1 @@
/etc/icwmpd/.icwmpd_backup_session.xml

View File

@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ieee1905
PKG_VERSION:=2.0.26
PKG_VERSION:=2.0.29
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=b7840dfe0b57cbdd47ec3167cbc7d2a6f9e41fd4
PKG_SOURCE_VERSION:=6e4666101c6927a163480c00fadc0bf2a6f8894c
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/ieee1905.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
endif

View File

@@ -5,7 +5,7 @@ config ieee1905 'ieee1905'
option macaddress 'auto'
option registrar 0
option cmdu_event 1
option map_plugin 0
option map_plugin 1
config security 'security'
list method 'PBC'

View File

@@ -1,7 +1,7 @@
#!/bin/sh /etc/rc.common
START=99
STOP=10
START=96
STOP=22
USE_PROCD=1
PROG=/usr/sbin/ieee1905d
@@ -43,6 +43,10 @@ configure_network()
fi
}
service_running() {
ubus -t 2 wait_for wifi
}
start_service() {
[ -d /usr/lib/ieee1905 ] || mkdir -p /usr/lib/ieee1905
@@ -64,5 +68,5 @@ service_triggers() {
procd_add_reload_trigger "network"
procd_add_reload_trigger "wireless"
procd_add_reload_trigger "netmode"
procd_add_config_trigger "config.change" "ieee1905" /etc/init.d/ieee1905 restart
procd_add_reload_trigger "ieee1905"
}

View File

@@ -7,6 +7,7 @@ CONFIG_PACKAGE_6in4=y
CONFIG_PACKAGE_6rd=y
CONFIG_PACKAGE_6to4=y
CONFIG_PACKAGE_alsa-lib=y
CONFIG_PACKAGE_bulkdata=y
CONFIG_PACKAGE_chat=y
CONFIG_PACKAGE_comgt=y
CONFIG_PACKAGE_comgt-directip=y
@@ -18,7 +19,7 @@ CONFIG_PACKAGE_fatrace=y
CONFIG_PACKAGE_gdb=m
CONFIG_PACKAGE_getopt=y
CONFIG_PACKAGE_glib2=y
CONFIG_PACKAGE_icwmp-curl=y
CONFIG_PACKAGE_icwmp=y
CONFIG_PACKAGE_ieee1905=y
CONFIG_PACKAGE_map-1905=y
CONFIG_PACKAGE_map-topology=y
@@ -83,7 +84,7 @@ CONFIG_PACKAGE_relayd=y
CONFIG_PACKAGE_resolveip=y
CONFIG_PACKAGE_rpcd=y
CONFIG_PACKAGE_rpcd-mod-rpcsys=y
CONFIG_PACKAGE_rsync=y
CONFIG_PACKAGE_rsync=m
CONFIG_PACKAGE_rulengd=y
CONFIG_PACKAGE_strace=y
CONFIG_PACKAGE_swmodd=m
@@ -96,6 +97,7 @@ CONFIG_PACKAGE_uqmi=y
CONFIG_PACKAGE_usb-modeswitch=y
CONFIG_PACKAGE_usbreset=y
CONFIG_PACKAGE_uspd=y
CONFIG_PACKAGE_vsftpd-tls=m
CONFIG_PACKAGE_wget=y
CONFIG_PACKAGE_wwan=y
CONFIG_PACKAGE_wifimngr=y

View File

@@ -188,10 +188,10 @@ function genconfig {
bcmAllowed=0
endptAllowed=0
natalieAllowed=0
mediatekAllowed=0
#mediatekAllowed=0
git ls-remote git@dev.iopsys.eu:broadcom/bcmcreator.git -q 2>/dev/null && bcmAllowed=1
git ls-remote git@dev.iopsys.eu:mediatek/linux.git -q 2>/dev/null && mediatekAllowed=1
#git ls-remote git@dev.iopsys.eu:mediatek/linux.git -q 2>/dev/null && mediatekAllowed=1
git ls-remote git@dev.iopsys.eu:dialog/natalie-dect-12.26.git -q 2>/dev/null && natalieAllowed=1
git ls-remote git@dev.iopsys.eu:iopsys/endptmngr.git -q 2>/dev/null && endptAllowed=1
}
@@ -411,13 +411,13 @@ function genconfig {
[ $bcmAllowed -eq 0 ] && echo "CONFIG_BCM_OPEN=y" >> .config
[ $endptAllowed -eq 0 ] && echo "CONFIG_ENDPT_OPEN=y" >> .config
[ $natalieAllowed -eq 0 ] && echo "CONFIG_NATALIE_OPEN=y" >> .config
[ $mediatekAllowed -eq 0 ] && echo "CONFIG_MEDIATEK_OPEN=y" >> .config
#[ $mediatekAllowed -eq 0 ] && echo "CONFIG_MEDIATEK_OPEN=y" >> .config
else
echo "# CONFIG_GITMIRROR_REWRITE is not set" >>.config
echo "CONFIG_BCM_OPEN=y" >> .config
echo "CONFIG_ENDPT_OPEN=y" >> .config
echo "CONFIG_NATALIE_OPEN=y" >> .config
echo "CONFIG_MEDIATEK_OPEN=y" >> .config
#echo "CONFIG_MEDIATEK_OPEN=y" >> .config
fi
if [ -n "$BRCM_MAX_JOBS" ]

View File

@@ -1,21 +1,32 @@
#!/bin/bash
# shellcheck disable=SC2029
build_bcmkernel_consumer() {
local tarfile bcmkernelcommith sdkversion
sdkversion=$(grep "CONFIG_BRCM_SDK_VER.*=y" .config | awk -F'[_,=]' '{print$5}')
sdkversion=${sdkversion:0:4}${sdkversion:(-1)}
bcmkernelcommith=$(grep -w "PKG_SOURCE_VERSION:" $curdir/feeds/broadcom/bcmkernel/${sdkversion:0:5}*.mk | cut -d'=' -f2)
local tarfile bcmkernelcommith sdkversion serverpath serverlink
sdkversion="$(grep "CONFIG_BRCM_SDK_VER.*=y" .config | awk -F'[_,=]' '{print$5}')"
sdkversion="${sdkversion:0:4}${sdkversion:(-1)}"
bcmkernelcommith="$(grep -w "PKG_SOURCE_VERSION:" "$curdir/feeds/broadcom/bcmkernel/${sdkversion:0:5}"*".mk" | cut -d'=' -f2)"
[ -n "$board" ] && [ -n "$bcmkernelcommith" ] || return
serverpath="$FPATH/bcmopen-$board-$bcmkernelcommith.tar.gz"
serverlink="$FPATH/bcmopen-$board-$majver.$minver-latest"
# do not build bcmopen sdk if it was already built before
[ -n "$board" -a -n "$bcmkernelcommith" ] || return
ssh $SERVER "test -f $FPATH/bcmopen-$board-$bcmkernelcommith.tar.gz" && return
cd ./build_dir/target-*/bcmkernel-*-${sdkversion:0:4}*/bcm963xx/release
bash do_consumer_release -p $profile -y -F
# if it was, check if there's a symlink in place and create it if missing
ssh "$SERVER" "test -f '$serverpath' && { test -L '$serverlink' || ln -sf '$serverpath' '$serverlink'; }" && return
cd "./build_dir/target-"*"/bcmkernel-"*"-${sdkversion:0:4}"*"/bcm963xx/release"
bash do_consumer_release -p "$profile" -y -F
tarfile='out/bcm963xx_*_consumer.tar.gz'
[ $(ls -1 $tarfile |wc -l) -ne 1 ] && echo "Too many tar files: '$tarfile'" && return
scp -pv $tarfile $SERVER:$FPATH/bcmopen-$board-$bcmkernelcommith.tar.gz
ssh $SERVER "[ -f $FPATH/bcmopen-$board-$bcmkernelcommith.tar.gz ] && ln -sf $FPATH/bcmopen-$board-$bcmkernelcommith.tar.gz $FPATH/bcmopen-$board-$majver.$minver-latest"
[ $(ls -1 $tarfile | wc -l) -ne 1 ] && echo "Too many tar files: '$tarfile'" && return
scp -pv $tarfile "$SERVER":"$serverpath"
ssh "$SERVER" "test -f '$serverpath' && ln -sf '$serverpath' '$serverlink'"
rm -f $tarfile
cd "$curdir"
}
@@ -25,7 +36,7 @@ build_natalie_consumer() {
grep -q "CONFIG_TARGET_NO_DECT=y" .config && return
natalieversion=$(grep -w "PKG_VERSION:" ./feeds/iopsys/natalie-dect/Makefile | cut -d'=' -f2)
nataliecommith=$(grep -w "PKG_SOURCE_VERSION:" ./feeds/iopsys/natalie-dect/Makefile | cut -d'=' -f2)
[ -n "$profile" -a -n "$natalieversion" -a -n "$nataliecommith" ] || return
[ -n "$profile" ] && [ -n "$natalieversion" ] && [ -n "$nataliecommith" ] || return
ssh $SERVER "test -f $FPATH/natalie-dect-$profile-$natalieversion-$nataliecommith.tar.gz" && return
cd ./build_dir/target-*/natalie-dect-$natalieversion/
mkdir natalie-dect-open-$natalieversion
@@ -44,7 +55,7 @@ build_endptmngr_consumer() {
grep -q "CONFIG_TARGET_NO_VOICE=y" .config && return
endptversion=$(grep -w "PKG_VERSION:" ./feeds/iopsys/endptmngr/Makefile | cut -d'=' -f2)
endptcommith=$(grep -w "PKG_SOURCE_VERSION:" ./feeds/iopsys/endptmngr/Makefile | cut -d'=' -f2)
[ -n "$profile" -a -n "$endptversion" -a -n "$endptcommith" ] || return
[ -n "$profile" ] && [ -n "$endptversion" ] && [ -n "$endptcommith" ] || return
ssh $SERVER "test -f $FPATH/endptmngr-$profile-$endptversion-$endptcommith.tar.gz" && return
cd ./build_dir/target-*/endptmngr-$endptversion/
mkdir endptmngr-open-$endptversion
@@ -85,7 +96,7 @@ build_mediatek_wifi_consumer() {
ver=$(grep -w "PKG_VERSION:" ./feeds/mediatek/mt${chip}/Makefile | cut -d'=' -f2)
commit=$(grep -w "PKG_SOURCE_VERSION:" ./feeds/mediatek/mt${chip}/Makefile | cut -d'=' -f2)
[ -n "$ver" -a -n "$commit" ] || return
[ -n "$ver" ] && [ -n "$commit" ] || return
ssh $SERVER "test -f $FPATH/mtk${chip}e-${ver}_${commit}.tar.xz" && return
cd build_dir/target-mipsel_1004kc*/linux-iopsys-ramips*/mtk${chip}e-$ver/ipkg-*
mkdir -p mtk${chip}e-$ver/src
@@ -112,7 +123,6 @@ function generate_tarballs {
set -e
git remote -v | grep -q http && return # do not continue if this is an open SDK environment
target=$(grep CONFIG_TARGET_BOARD .config | cut -d'=' -f2 | tr -d '"')
board=$(grep CONFIG_TARGET_FAMILY .config | cut -d'=' -f2 | tr -d '"')
profile=$(grep CONFIG_BCM_KERNEL_PROFILE .config | cut -d'=' -f2 | tr -d '"')
majver=$(grep CONFIG_TARGET_VERSION .config | cut -d'=' -f2 | tr -d '"' | cut -f1 -d .)
@@ -137,7 +147,7 @@ function generate_tarballs {
esac
done
if [ ! -n "$stk_target" ]; then
if [ -z "$stk_target" ]; then
print_usage
exit 1
fi

View File

@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=map-1905
PKG_VERSION:=0.0.10
PKG_VERSION:=0.0.11
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=7cdc6d38674bef2c6003a4b60b63be8a789421be
PKG_SOURCE_VERSION:=bf13ed6117078177e9ba170b671d25afc044f246
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/map-1905.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
endif

View File

@@ -6,11 +6,11 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=map-topology
PKG_VERSION:=1.4.2
PKG_VERSION:=1.5.6
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_VERSION:=e22b79c1a1ec443fcc816439658fb4e8cedf21fb
PKG_SOURCE_VERSION:=8d008ef712227986263e9a2a1b188ce3a27e17f8
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/map-topology.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
@@ -23,7 +23,8 @@ include $(INCLUDE_DIR)/package.mk
define Package/map-topology
CATEGORY:=Utilities
DEPENDS:=+libubox +ubus +libpthread +libuci +libeasy +libieee1905
DEPENDS:=+libubox +ubus +libpthread +libuci +libeasy \
+libieee1905 +libavahi-nodbus-support
TITLE:=Utility to build topology of a multi-AP network
endef

View File

@@ -1,5 +1,5 @@
config topology
config topology 'topology'
option enabled '1'
option depth '8'
option interval '60'

View File

@@ -1,7 +1,7 @@
#!/bin/sh /etc/rc.common
START=14
STOP=96
START=97
STOP=21
USE_PROCD=1

View File

@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=obuspa
PKG_VERSION:=2.0.21
PKG_VERSION:=2.0.22
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=25b920c13160360de16300a8d04a068feb197c50
PKG_SOURCE_VERSION:=06270b7a45b77d6d883eb244e6d854efce10f17f
PKG_SOURCE_URL:=https://dev.iopsys.eu/fork/obuspa.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
endif

View File

@@ -5,6 +5,8 @@ IP_RULE=""
BR_RULE=""
is_bcm968=0
POLICER_COUNT=0
#function to handle a queue section
handle_queue() {
qid="$1" #queue section ID
@@ -69,6 +71,31 @@ handle_queue() {
echo $q_no > /tmp/qos/queue_stats/$ifname/q_idx
}
#function to handle a policer section
handle_policer() {
local p_sec="$1" # policer section ID
local dir=1 # default direction, upstream
config_get is_enable "$p_sec" "enable"
#no need to configure disabled policer
if [ $is_enable == '0' ]; then
return
fi
config_get cir "$p_sec" "committed_rate"
config_get cbs "$p_sec" "committed_burst_size" -1
config_get ebs "$p_sec" "excess_burst_size" 0
config_get pir "$p_sec" "peak_rate" 0
config_get pbs "$p_sec" "peak_burst_size" 0
config_get meter "$p_sec" "meter_type" 0
# Call tmctl which is a broadcomm command to configure policer.
tmctl createpolicer --dir $dir --pid $POLICER_COUNT --ptype $meter --cir $cir --cbs $cbs --ebs $ebs --pir $pir --pbs $pbs
POLICER_COUNT=$((POLICER_COUNT + 1))
}
#function to handle a shaper section
handle_shaper() {
sid="$1" #queue section ID
@@ -422,6 +449,64 @@ handle_iptables_rules() {
fi
}
handle_policer_rules() {
local c_sec=$1
local policer_name
local ifname
local pname
local pindex=-1
config_get policer_name "$c_sec" "policer"
if [ -z "$policer_name" ];then
# no need to apply policer if policer not present in this
# classification rule
return
fi
config_get ifname "$c_sec" "ifname"
if [ -z "$ifname" ]; then
# cannot associate policer as interface is not mentioned
return
fi
local i=0
local max_policer_inst=$(cat /tmp/qos/max_policer_inst)
while :
do
if [ $i -eq $max_policer_inst ]; then
break
fi
pname="$(uci -q get qos.@policer[$i].name)"
if [ "$policer_name" == "$pname" ]; then
pindex=$i
break
fi
i=$((i + 1))
done
if [ $pindex -lt 0 ]; then
# policer not found, no need to proceed further
return
fi
local portorder="$(db -q get hw.board.ethernetPortOrder)"
local wanport="$(db -q get hw.board.ethernetWanPort)"
i=0
for port in $portorder; do
if [ "$ifname" == "$port" ]; then
if [ "$wanport" == "$port" ]; then
bs /b/configure port/index=wan0 ingress_rate_limit={traffic_types=8,policer={policer/dir=us,index=$pindex}}
else
bs /b/configure port/index=lan$i ingress_rate_limit={traffic_types=8,policer={policer/dir=us,index=$pindex}}
fi
break
fi
i=$((i + 1))
done
}
#function to handle a classify section
handle_classify() {
cid="$1" #classify section ID
@@ -434,6 +519,7 @@ handle_classify() {
handle_ebtables_rules $cid
handle_iptables_rules $cid
handle_policer_rules $cid
}
configure_shaper() {
@@ -496,9 +582,35 @@ configure_queue() {
config_foreach handle_queue queue
}
configure_policer() {
# Delete policer
local i=0
local max_p_inst=0
if [ -f "/tmp/qos/max_policer_inst" ]; then
max_p_inst=$(cat /tmp/qos/max_policer_inst)
fi
while :
do
if [ $i -eq $max_p_inst ]; then
break
fi
tmctl deletepolicer --dir 1 --pid $i &>/dev/null
i=$((i + 1))
done
# reset the policer counter
echo 0 > /tmp/qos/max_policer_inst
# Load UCI file
config_load qos
config_foreach handle_policer policer
echo $POLICER_COUNT > /tmp/qos/max_policer_inst
}
configure_qos() {
configure_queue
configure_shaper
configure_policer
configure_classify
}
@@ -512,6 +624,8 @@ reload_qos() {
configure_queue
elif [ "$service_name" == "classify" ]; then
configure_classify
elif [ "$service_name" == "policer" ]; then
configure_policer
fi
}

View File

@@ -6,9 +6,9 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=questd
PKG_VERSION:=5.1.11
PKG_VERSION:=5.1.12
PKG_SOURCE_VERSION:=6b64dafae52d0cd28a31d364aeed80380875293b
PKG_SOURCE_VERSION:=5de841c629d13bd8a5b90081343aaf5b75afc7c2
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/questd

42
stun/Makefile Executable file
View File

@@ -0,0 +1,42 @@
#
# Copyright (C) 2020 iopsys Software Solutions AB
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=stun
PKG_VERSION:=1.0.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=BBF stun Client
DEPENDS:=+libubus +libuci +libubox +libjson-c +libopenssl +libblobmsg-json
endef
define Package/$(PKG_NAME)/description
CWMP STUN Client
endef
define Build/Prepare
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += \
-D_GNU_SOURCE
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/stund $(1)/usr/sbin/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -0,0 +1,14 @@
config stun 'stun'
option enable '0'
option username 'stun'
option password 'stun'
option server_address 'stun.l.google.com'
option server_port '19302'
option min_keepalive '30'
option max_keepalive '3600'
# option client_port 7547
#if client_port option is not set or < 0 then use a random port for connection request source port
#Log levels: Critical=0, Warning=1, Notice=2, Info=3, Debug=4
option log_level '3'

36
stun/files/etc/init.d/stund Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/sh /etc/rc.common
# STUN client software
# Copyright (C) 2020 iopsys Software Solutions AB
# Author: Omar Kallel <omar.kallel@pivasoftware.com>
START=90
USE_PROCD=1
PROG="/usr/sbin/stund"
start_service() {
local enable=`uci -q get stun.stun.enable`
if [ "$enable" == "1" ]; then
local server=`uci -q get stun.stun.server_address`
[ "$server" = "" ] && exit 0
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn "3" "7" "0"
procd_close_instance
fi
}
boot() {
start
}
reload_service() {
logger -p crit -t "stun" "reloading service()"
stop
start
}
service_triggers()
{
procd_add_reload_trigger stun
}

16
stun/src/Makefile Normal file
View File

@@ -0,0 +1,16 @@
PROG = stund
OBJS = stun.o config.o log.o ubus.o
PROG_CFLAGS = $(CFLAGS) -Wall -Werror
PROG_LDFLAGS = $(LDFLAGS) -lubus -luci -lubox -ljson-c -lcrypto -lblobmsg_json
%.o: %.c
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
clean:
rm -f *.o $(PROG)

297
stun/src/config.c Normal file
View File

@@ -0,0 +1,297 @@
/*
* config.c -- contains functions that allows reading and loading of uci config parameters of stun
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "config.h"
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
static struct uci_context *uci_ctx = NULL;
static struct uci_context *uci_ctx_state = NULL;
struct stun_config conf;
int config_fini(void)
{
free(conf.server_address);
free(conf.password);
free(conf.username);
conf.server_address = NULL;
conf.username = NULL;
conf.password = NULL;
return 0;
}
int config_init(void)
{
char *v;
suci_init();
memset(&conf, 0, sizeof(struct stun_config));
v = suci_get_value("stun", "stun", "server_address");
if (!*v) {
stun_log(SCRIT, "Missing Server Address in the STUN config");
goto error;
}
conf.server_address = strdup(v);
v = suci_get_value("stun", "stun", "username");
if (*v)
conf.username = strdup(v);
v = suci_get_value("stun", "stun", "password");
if (*v)
conf.password = strdup(v);
v = suci_get_value("stun", "stun", "server_port");
if (*v)
conf.server_port = atoi(v);
else
conf.server_port = DEFAULT_SERVERPORT;
v = suci_get_value("stun", "stun", "log_level");
if (*v)
conf.loglevel = atoi(v);
else
conf.loglevel = DEFAULT_LOGLEVEL;
v = suci_get_value("stun", "stun", "min_keepalive");
if (*v)
conf.min_keepalive = atoi(v);
else
conf.min_keepalive = DEFAULT_MINKEEPALIVE;
v = suci_get_value("stun", "stun", "max_keepalive");
if (*v)
conf.max_keepalive = atoi(v);
else
conf.max_keepalive = DEFAULT_MAXKEEPALIVE;
v = suci_get_value("stun", "stun", "client_port");
if (*v)
conf.client_port = atoi(v);
if (conf.max_keepalive <= 0)
conf.max_keepalive = DEFAULT_MAXKEEPALIVE;
if (conf.min_keepalive <= 0)
conf.min_keepalive = DEFAULT_MINKEEPALIVE;
if (conf.server_port <= 0)
conf.server_port = DEFAULT_SERVERPORT;
if (conf.loglevel >= __MAX_SLOG || conf.loglevel < 0) {
conf.loglevel = DEFAULT_LOGLEVEL;
}
stun_log(SINFO, "STUN CONFIG - Server Address: %s", conf.server_address);
stun_log(SINFO, "STUN CONFIG - Username: %s", conf.username ? conf.username : "<not defined>");
stun_log(SINFO, "STUN CONFIG - Server port: %d", conf.server_port);
stun_log(SINFO, "STUN CONFIG - min keepalive: %d", conf.min_keepalive);
stun_log(SINFO, "STUN CONFIG - max keepalive: %d", conf.max_keepalive);
stun_log(SINFO, "STUN CONFIG - Client port: %d", (conf.client_port > 0) ? conf.client_port : -1);
stun_log(SINFO, "STUN CONFIG - LOG Level: %d (Critical=0, Warning=1, Notice=2, Info=3, Debug=4)", conf.loglevel);
suci_fini();
return 0;
error:
suci_fini();
config_fini();
exit(1);
}
int suci_init(void)
{
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
return -1;
}
uci_ctx_state = uci_alloc_context();
if (!uci_ctx_state) {
return -1;
}
uci_add_delta_path(uci_ctx_state, uci_ctx_state->savedir);
uci_set_savedir(uci_ctx_state, VAR_STATE);
return 0;
}
int suci_fini(void)
{
if (uci_ctx) {
uci_free_context(uci_ctx);
}
if (uci_ctx_state) {
uci_free_context(uci_ctx_state);
}
uci_ctx = NULL;
uci_ctx_state = NULL;
return 0;
}
static bool suci_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 suci_init_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *package, char *section, char *option, char *value)
{
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 && !suci_validate_section(ptr->section))
ptr->flags |= UCI_LOOKUP_EXTENDED;
return 0;
error:
return -1;
}
void suci_print_list(struct uci_list *uh, char **val, char *delimiter)
{
struct uci_element *e;
static char buffer[512];
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;
}
char *suci_get_value(char *package, char *section, char *option)
{
struct uci_ptr ptr;
char *val = "";
if (!section || !option)
return val;
if (suci_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) {
suci_print_list(&ptr.o->v.list, &val, " ");
return val;
}
if (ptr.o->v.string)
return ptr.o->v.string;
else
return val;
}
char *suci_set_value(char *package, char *section, char *option, char *value)
{
struct uci_ptr ptr;
int ret = UCI_OK;
if (!section)
return "";
if (suci_init_ptr(uci_ctx, &ptr, package, section, option, value))
return "";
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
return "";
uci_set(uci_ctx, &ptr);
if (ret == UCI_OK)
ret = uci_save(uci_ctx, ptr.p);
if (ptr.o && ptr.o->v.string)
return ptr.o->v.string;
return "";
}
/*************************---/var/state--***************************/
char *suci_get_value_state(char *package, char *section, char *option)
{
char *val;
struct uci_context *save_uci_ctx = uci_ctx;
uci_ctx = uci_ctx_state;
val = suci_get_value(package, section, option);
uci_ctx = save_uci_ctx;
return val;
}
char *suci_set_value_state(char *package, char *section, char *option, char *value)
{
char *val;
struct uci_context *save_uci_ctx = uci_ctx;
uci_ctx = uci_ctx_state;
val = suci_set_value(package, section, option, value);
uci_ctx = save_uci_ctx;
return val;
}

44
stun/src/config.h Normal file
View File

@@ -0,0 +1,44 @@
/* TR-069 STUN client software
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*/
#ifndef __CONFIG_H
#define __CONFIG_H
#include <uci.h>
#include "log.h"
#define VAR_STATE "/var/state"
#define DEFAULT_SERVERPORT 3478
#define DEFAULT_CLIENTPORT 7547
#define DEFAULT_MINKEEPALIVE 30
#define DEFAULT_RETRYTIME 3
#define DEFAULT_MAXKEEPALIVE 3600
#define DEFAULT_LOGLEVEL SINFO
struct stun_config {
char *server_address;
char *username;
char *password;
int server_port;
int client_port;
int max_keepalive;
int min_keepalive;
int loglevel;
};
extern struct stun_config conf;
int config_init(void);
int config_fini(void);
int suci_init(void);
int suci_fini(void);
void suci_print_list(struct uci_list *uh, char **val, char *delimiter);
char *suci_get_value(char *package, char *section, char *option);
char *suci_set_value(char *package, char *section, char *option, char *value);
char *suci_get_value_state(char *package, char *section, char *option);
char *suci_set_value_state(char *package, char *section, char *option, char *value);
#endif //__CONFIG_H

68
stun/src/log.c Normal file
View File

@@ -0,0 +1,68 @@
/*
* log.c : conatains function used log traces
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <syslog.h>
#include <time.h>
#include "log.h"
#include "config.h"
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 stun_log(int priority, const char *format, ...)
{
va_list vl;
if (priority <= conf.loglevel) {
time_t t = time(NULL);
struct tm tm = *localtime(&t);
va_start(vl, format);
printf("%d-%02d-%02d %02d:%02d:%02d [stun] %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");
openlog("stun", 0, LOG_DAEMON);
va_start(vl, format);
vsyslog(log_syslogmap[priority], format, vl);
va_end(vl);
closelog();
}
}

20
stun/src/log.h Normal file
View File

@@ -0,0 +1,20 @@
/* TR-069 STUN client software
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*/
#ifndef __SLOG_H
#define __SLOG_H
enum stun_log_level_enum {
SCRIT,
SWARNING,
SNOTICE,
SINFO,
SDEBUG,
__MAX_SLOG
};
void stun_log(int priority, const char *format, ...);
#endif //__SLOG_H

687
stun/src/stun.c Normal file
View File

@@ -0,0 +1,687 @@
/*
* stun.c -- the main file of stun application
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* TR-069 STUN client software
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
* Author: Mohamed Kallel <mohamed.kallel@pivasoftware.com>
* Omar Kallel <omar.kallel@pivasoftware.com>
* Anis Ellouze <anis.ellouze@pivasoftware.com>
*/
#include <stdio.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/un.h>
#include <stdlib.h>
#include <libubox/uloop.h>
#include <openssl/hmac.h>
#include <string.h>
#include <ifaddrs.h>
#include "stun.h"
#include "config.h"
#include "ubus.h"
struct env_var env = {0};
int keepalive_timeout = DEFAULT_MINKEEPALIVE;
int retry_timeout = DEFAULT_RETRYTIME;
int bindcrreusaddr = 1;
int bindcrreusport = 1;
const char *BBFCR = "dslforum.org/TR-111 ";
static void stun_notify_cb(struct uloop_timeout *timeout);
static void stun_inform_cb(struct uloop_timeout *timeout);
static void listening_crport_cb(struct uloop_timeout *timeout);
static void binding_request_crport_cb(struct uloop_timeout *timeout);
static struct udp_listen listen_crport = {
.fd = -1,
.utimer = {.cb = listening_crport_cb}
};
static struct binding_request br_crport = {
.binding_cr = 1,
.udp_listen = &listen_crport,
.utimer = {.cb = binding_request_crport_cb}
};
static struct binding_request br_crport_keepalive = {
.is_keealive = 1,
.binding_cr = 1,
.udp_listen = &listen_crport,
.utimer = {.cb = binding_request_crport_cb}
};
struct uloop_timeout stun_notify_timer = {.cb = stun_notify_cb};
struct uloop_timeout stun_inform_timer = {.cb = stun_inform_cb};
void stun_notify(int afterms)
{
uloop_timeout_set(&stun_notify_timer, afterms);
}
void stun_inform(int afterms)
{
uloop_timeout_set(&stun_inform_timer, afterms);
}
static void stun_notify_cb(struct uloop_timeout *timeout)
{
stun_log(SINFO, "ubus call tr069 notify");
if (subus_call("tr069", "notify", 0, UBUS_ARGS{}) < 0) {
stun_log(SINFO, "ubus call tr069 notify failed! retry after 1s");
stun_notify(1000);
}
}
static void stun_inform_cb(struct uloop_timeout *timeout)
{
stun_log(SINFO, "ubus call tr069 inform '{\"event\": \"6 connection request\"}'");
if (subus_call("tr069", "inform", 1, UBUS_ARGS{{"event", "6 connection request"}}) < 0) {
stun_log(SINFO, "ubus call tr069 inform '{\"event\": \"6 connection request\"}' failed! retry after 1s");
stun_inform(1000);
}
}
static int stunid_cmp(stunid *left, stunid *right)
{
return memcmp(left, right, sizeof(*left));
}
static void *stunid_cpy(stunid *left, stunid *right)
{
return memcpy(left, right, sizeof(*left));
}
static void stunid_rand(stunid *id)
{
int i;
srand(time(NULL));
for (i = 0; i < 4; i++)
{
id->id[i] = rand();
}
}
ssize_t timeout_recvfrom(int sock, char *buf, int length, struct sockaddr_in *connection, int timeoutinseconds)
{
fd_set socks;
ssize_t r = 0;
struct timeval t = {0};
int clen = sizeof(*connection);
stun_log(SDEBUG, "udp revcfrom, timeout: %ds", timeoutinseconds);
FD_ZERO(&socks);
FD_SET(sock, &socks);
t.tv_sec = timeoutinseconds;
if (select(sock + 1, &socks, NULL, NULL, &t) &&
(r = recvfrom(sock, buf, length, 0, (struct sockaddr *)connection, (socklen_t *)&clen)) != -1) {
return r;
}
else {
return -1;
}
}
static int stun_send(int s, char *buf)
{
struct stun_header *sh;
struct hostent *he;
struct sockaddr_in dst = {0};
sh = (struct stun_header *)buf;
if ((he = gethostbyname(conf.server_address)) == NULL) {
return -1;
}
memcpy(&(dst.sin_addr), he->h_addr_list[0], he->h_length);
dst.sin_port = htons(conf.server_port);
dst.sin_family = AF_INET;
stun_log(SINFO, "send STUN message to %s:%u (%s:%u)", conf.server_address, conf.server_port, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port));
return sendto(s, buf, ntohs(sh->len) + sizeof(*sh), 0, (struct sockaddr *)&dst, sizeof(dst));
}
static int net_socket(int srcport)
{
int sock = -1;
stun_log(SINFO, "Open UDP socket");
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock >= 0) {
if (srcport > 0) {
struct sockaddr_in bindcraddr = {0};
int i = 0;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &bindcrreusaddr, sizeof(int)) < 0) {
stun_log(SWARNING, "setsockopt(SO_REUSEADDR) failed");
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &bindcrreusport, sizeof(int)) < 0) {
stun_log(SWARNING, "setsockopt(SO_REUSEPORT) failed");
}
bindcraddr.sin_family = AF_INET;
bindcraddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindcraddr.sin_port = htons((unsigned short)srcport);
for(;i<9;i++)
{
if (bind(sock, (struct sockaddr *)&bindcraddr, sizeof(bindcraddr)) < 0) {
continue;
}
stun_log(SINFO, "binding socket source port to %u", srcport);
break;
}
}
fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
}
return sock;
}
static void stun_close_socket(struct udp_listen *udp_listen)
{
uloop_timeout_cancel(&udp_listen->utimer);
if (udp_listen->fd > 0) {
stun_log(SINFO, "STUN close socket %d", udp_listen->fd);
close(udp_listen->fd);
}
udp_listen->fd = -1;
}
static void stun_socket(struct udp_listen *udp_listen)
{
if (udp_listen->fd > 0) {
stun_close_socket(udp_listen);
}
udp_listen->fd = net_socket(conf.client_port);
stun_log(SINFO, "STUN new socket %d", udp_listen->fd);
uloop_timeout_set(&udp_listen->utimer, 0);
}
static int trailing_buffer_alloc(int mp, char *buf, int len, char trail, char **bufm, int *mlen)
{
*bufm = NULL;
*mlen = len % mp;
*mlen = len + (*mlen ? (mp - *mlen) : 0);
*bufm = calloc(1, *mlen);
if (*bufm == NULL)
return -1;
memcpy(*bufm, buf, len);
if (trail) {
while(len < *mlen) {
(*bufm)[len++] = trail;
}
}
return 0;
}
static int append_attribute_buffer(unsigned char **start, char *buf, int len, unsigned short attr_type, int free)
{
if ((sizeof(struct stun_attribute) + len) > free)
return -1;
struct stun_attribute *sa = (struct stun_attribute *)*start;
sa->len = htons((unsigned short)len);
sa->type = htons(attr_type);
memcpy(sa->value, buf, len);
*start += sizeof(struct stun_attribute) + len;
return 0;
}
static int stun_hmac(int trailing_mp, unsigned char *data, int len, char *password, char *hmac)
{
char *bufmp = NULL;
int lenmp;
unsigned char* digest;
if (trailing_mp) {
if (trailing_buffer_alloc(trailing_mp, (char *)data, len, 0, &bufmp, &lenmp))
return -1;
digest = HMAC(EVP_sha1(), password, strlen(password), (unsigned char *)bufmp, lenmp, NULL, NULL);
free(bufmp);
}
else {
digest = HMAC(EVP_sha1(), password, strlen(password), data, len, NULL, NULL);
}
memcpy(hmac, digest, 20);
return 0;
}
static void hex_to_str(char *hex, int len, char *str)
{
while (len--) {
sprintf(str, "%02X", *hex++);
str += 2;
}
}
static int generate_stun_packet(struct binding_request *br, char *req_buf, int maxlen)
{
struct stun_header *req;
unsigned char *stunmsg;
req = (struct stun_header *) req_buf;
stunmsg = req->stunmsg;
stun_log(SINFO, "STUN generate BINDING-REQUEST");
req->type = htons(BINDING_REQUSET);
stunid_rand(&(req->id));
stunid_cpy(&(br->id), &(req->id));
stun_log(SINFO, "STUN request id: %d%d%d%d", req->id.id[0], req->id.id[1], req->id.id[2], req->id.id[3]);
if (conf.username) {
char *buf4;
int len4;
if (trailing_buffer_alloc(4, conf.username, strlen(conf.username), ' ', &buf4, &len4))
return -1;
append_attribute_buffer(&stunmsg, buf4, len4, ATTR_USERNAME, (maxlen - (stunmsg - (unsigned char *)req)));
stun_log(SINFO, "STUN append USERNAME: **%.*s**", len4, buf4);
free(buf4);
}
if (br->binding_cr) {
stun_log(SINFO, "STUN append CONNECTION-REQUEST-BINDING: **%s**", BBFCR);
append_attribute_buffer(&stunmsg, (char *)BBFCR, strlen(BBFCR), ATTR_CONNECTION_REQUEST_BINDING, (maxlen - (stunmsg - (unsigned char *)req)));
}
if (br->binding_change) {
stun_log(SINFO, "STUN append BINDING-CHANGE");
append_attribute_buffer(&stunmsg, "", 0, ATTR_BINDING_CHANGE, (maxlen - (stunmsg - (unsigned char *)req)));
}
if (br->msg_integrity) {
if (conf.username) {
char *password;
char hmac[20] = {0};
char hmacstr[64];
req->len = htons((stunmsg - (unsigned char *)req) - sizeof(struct stun_header) + sizeof(struct stun_attribute) + 20);
password = conf.password ? conf.password : "";
stun_hmac(64, (unsigned char *)req, stunmsg - (unsigned char *)req, password, hmac);
append_attribute_buffer(&stunmsg, hmac, sizeof(hmac), ATTR_MESSAGE_INTEGRITY, (maxlen - (stunmsg - (unsigned char *)req)));
hex_to_str(hmac, 20, hmacstr);
stun_log(SINFO, "STUN append MESSAGE-INTEGRITY: ***%s***", hmacstr);
}
else {
req->len = htons((stunmsg - (unsigned char *)req) - sizeof(struct stun_header));
br->msg_integrity = 0;
return -1;
}
}
else {
req->len = htons((stunmsg - (unsigned char *)req) - sizeof(struct stun_header));
}
stun_log(SINFO, "STUN request length: %d", ntohs(req->len));
return 0;
}
static int stun_get_mapped_address(char *buf, unsigned int *ip, unsigned short *port)
{
struct stun_header *sh = (struct stun_header *)buf;
struct stun_attribute *sa = (struct stun_attribute *)sh->stunmsg;
char *p;
while (((char *)sa - (char *)sh - sizeof(*sh)) < ntohs(sh->len)) {
if(ntohs(sa->type) == ATTR_MAPPED_ADDRESS) {
struct stun_address *ma = (struct stun_address *)sa->value;
*port = ma->port;
*ip = ma->address;
return 0;
}
p = (char *)sa;
p += sizeof(struct stun_attribute) + ntohs(sa->len);
sa = (struct stun_attribute *)p;
}
return -1;
}
static int stun_get_error_code(char *buf)
{
struct stun_header *sh = (struct stun_header *)buf;
struct stun_attribute *sa = (struct stun_attribute *)sh->stunmsg;
char *p;
while (((char *)sa - (char *)sh - sizeof(*sh)) < ntohs(sh->len)) {
if(ntohs(sa->type) == ATTR_ERROR_CODE) {
unsigned int class, number;
unsigned int ui = ntohl(*((unsigned int *)sa->value));
class = (ui >> 8) & 0x7;
number = ui & 0xff;
return (int)(class * 100 + number);
}
p = (char *)sa;
p += sizeof(struct stun_attribute) + ntohs(sa->len);
sa = (struct stun_attribute *)p;
}
return 0;
}
static void handle_udp_cr(char *resp_buf)
{
char *str;
char un[64], cn[64], sig[64], buf[256];
char *crusername;
char *crpassword;
unsigned int crid = 0, ts = 0;
int valid = 1;
stun_log(SINFO, "Handle UDP Connection Request");
if ((str = strstr(resp_buf, "ts="))) {
sscanf(str, "ts=%u", &ts);
stun_log(SINFO, "UDP CR ts = %u", ts);
}
else {
stun_log(SWARNING, "UDP CR ts not found");
return;
}
if ((str = strstr(resp_buf, "id="))) {
sscanf(str, "id=%u", &crid);
stun_log(SINFO, "UDP CR id = %u", crid);
}
else {
return;
stun_log(SWARNING, "UDP CR id not found");
}
if (crid && ts && crid != env.last_crid && ts > env.last_ts) {
stun_log(SINFO, "NEW UDP CR");
env.last_crid = crid;
env.last_ts = ts;
if ((str = strstr(resp_buf, "un="))) {
sscanf(str, "un=%63[^?& \t\n\r]", un);
stun_log(SINFO, "UDP CR un = %s", un);
}
else {
stun_log(SWARNING, "UDP CR un not found");
return;
}
if ((str = strstr(resp_buf, "cn="))) {
sscanf(str, "cn=%63[^?& \t\n\r]", cn);
stun_log(SINFO, "UDP CR cn = %s", cn);
}
else {
stun_log(SWARNING, "UDP CR cn not found");
return;
}
if ((str = strstr(resp_buf, "sig="))) {
sscanf(str, "sig=%63[^?& \t\n\r]",sig);
stun_log(SINFO, "UDP CR sig = %s", sig);
}
else {
stun_log(SWARNING, "UDP CR sig not found");
return;
}
suci_init();
crusername = suci_get_value("cwmp", "cpe", "userid");
crpassword = suci_get_value("cwmp", "cpe", "password");
if (*crusername && *crpassword) {
if (strcmp(crusername, un) != 0) {
stun_log(SINFO, "UDP CR username mismatch!");
valid = 0;
}
else {
char hmac[20], hmacstr[64];
snprintf(buf, sizeof(buf), "%u%u%s%s", ts, crid, un, cn);
stun_hmac(0, (unsigned char *)buf, strlen(buf), crpassword, hmac);
hex_to_str(hmac, 20, hmacstr);
if (strcasecmp(hmacstr, sig) != 0) {
stun_log(SINFO, "UDP CR sig mismatch!");
valid = 0;
}
}
}
suci_fini();
if (valid) {
stun_inform(0);
}
} else {
if (!ts || !crid)
stun_log(SINFO, "UDP CR ts or id not found");
else
stun_log(SINFO, "UDP CR ts is old or id is already received");
}
}
static void save_udpcr_var_state(unsigned int ip, unsigned short port)
{
struct in_addr ip_addr;
char buf[64];
ip_addr.s_addr = env.address;
snprintf(buf, sizeof(buf), "%s:%d", inet_ntoa(ip_addr), ntohs(env.port));
stun_log(SINFO, "Save New UDPConnectionRequestAddress to /var/state %s", buf);
suci_init();
suci_set_value_state("stun", "stun", "crudp_address", buf);
suci_fini();
}
static int is_udpcr_changed(unsigned int ip, unsigned short port)
{
struct in_addr ip_addr;
char buf[64];
char *v;
int changed = 0;
ip_addr.s_addr = ip;
snprintf(buf, sizeof(buf), "%s:%d", inet_ntoa(ip_addr), ntohs(port));
suci_init();
v = suci_get_value_state("stun", "stun", "crudp_address");
if (strcmp(buf, v) != 0)
changed = 1;
suci_fini();
return changed;
}
static void save_natdetected_var_state(unsigned int ip)
{
struct ifaddrs * ifaddrlist = NULL;
struct ifaddrs * ifa = NULL;
int islocal = 0;
char *nd;
getifaddrs(&ifaddrlist);
for (ifa = ifaddrlist; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa ->ifa_addr && ifa ->ifa_addr->sa_family == AF_INET) {
if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == ip) {
islocal = 1;
break;
}
}
}
if (ifaddrlist != NULL)
freeifaddrs(ifaddrlist);
suci_init();
nd = suci_get_value_state("stun", "stun", "nat_detected");
if (islocal && *nd != '\0') {
stun_log(SINFO, "Device is not behind NAT, set NATDetected to false");
suci_set_value_state("stun", "stun", "nat_detected", "");
}
else if (!islocal && *nd == '\0') {
stun_log(SINFO, "Device is behind NAT, set NATDetected to true");
suci_set_value_state("stun", "stun", "nat_detected", "1");
}
suci_fini();
}
static void binding_request_crport_cb(struct uloop_timeout *timeout)
{
struct binding_request *br;
struct udp_listen *udp_listen;
char req_buf[2048] = {0};
int r;
br = binding_request_entry(timeout);
udp_listen = br->udp_listen;
udp_listen->br = br;
stun_log(SINFO, "Binding Request cb start %s", br->is_keealive ? "(KeepAlive)" : "");
if (udp_listen->fd <= 0) {
stun_socket(udp_listen);
}
if (br->resp_success > 0)
br->resp_success = 0;
if (generate_stun_packet(br, req_buf, sizeof(req_buf) - 1)) {
br->retry_interval = (br->retry_interval) ? 2 * br->retry_interval : retry_timeout;
br->retry_interval = (br->retry_interval > 1500) ? 1500 : br->retry_interval;
uloop_timeout_set(&br->utimer, br->retry_interval * 1000);
return;
}
r = stun_send(udp_listen->fd, req_buf);
if (r < 0) {
stun_close_socket(udp_listen);
udp_listen->br = NULL;
br->retry_interval = (br->retry_interval) ? 2 * br->retry_interval : retry_timeout;
br->retry_interval = (br->retry_interval > 1500) ? 1500 : br->retry_interval;
stun_log(SINFO, "Failed send of Binding Request! retry in %ds", br->retry_interval);
uloop_timeout_set(timeout, br->retry_interval * 1000);
}
else {
br->retry_interval = 0;
stun_log(SINFO, "Success send of Binding Request.");
stun_log(SINFO, "Start KeepAlive Binding Request in %ds.", keepalive_timeout);
uloop_timeout_set(&br_crport_keepalive.utimer, keepalive_timeout * 1000);
}
}
static void listening_crport_cb(struct uloop_timeout *timeout)
{
struct udp_listen *udp_listen;
struct sockaddr_in src = {0};
char resp_buf[2048] = {0};
unsigned int ip = 0;
unsigned short port = 0;
int r;
stun_log(SDEBUG, "Binding listening CR cb start");
udp_listen = udp_listen_entry(timeout);
if (udp_listen->fd < 0) {
stun_log(SINFO, "Binding listening CR: Socket = -1");
uloop_timeout_set(timeout, 19);
return;
}
r = timeout_recvfrom(udp_listen->fd, resp_buf, sizeof(resp_buf) - 1, &src, 1);
if (r > 0) {
stun_log(SINFO, "Binding listening CR: get UDP packet");
struct stun_header *sh = (struct stun_header *)resp_buf;
if (ntohs(sh->type) == BINDING_ERROR) {
int code = stun_get_error_code(resp_buf);
stun_log(SINFO, "get BINDING-ERROR: code is %d", code);
if (udp_listen->br != NULL && stunid_cmp(&(sh->id), &(udp_listen->br->id)) == 0 && code == 401) {
udp_listen->br->msg_integrity = 1;
udp_listen->br->auth_fail++;
stun_log(SINFO, "Cancel scheduled Keepalive Binding Request");
uloop_timeout_cancel(&br_crport_keepalive.utimer);
stun_log(SINFO, "Trying new Binding Request in %ds",
(udp_listen->br->auth_fail < 3) ? 0 : (udp_listen->br->auth_fail - 2)*3);
uloop_timeout_set(&udp_listen->br->utimer,
(udp_listen->br->auth_fail < 3) ? 0 : ((udp_listen->br->auth_fail - 2) * 3000));
udp_listen->br = NULL;
}
else if (code != 401) {
stun_log(SINFO, "Unsupported error code");
}
goto end;
}
else if (ntohs(sh->type) == BINDING_RESPONSE) {
struct in_addr ip_addr;
stun_log(SINFO, "get BINDING-RESPONSE");
if (udp_listen->br != NULL && stunid_cmp(&(sh->id), &(udp_listen->br->id)) == 0) {
udp_listen->br->resp_success = 1;
udp_listen->br->msg_integrity = 0;
udp_listen->br->auth_fail = 0;
stun_get_mapped_address(resp_buf, &ip, &port);
ip_addr.s_addr = ip;
stun_log(SINFO, "Mapped Address is: %s:%u", inet_ntoa(ip_addr), ntohs(port));
save_natdetected_var_state(ip);
if (is_udpcr_changed(ip, port)) {
env.address = ip;
env.port = port;
udp_listen->br->resp_success = 0;
udp_listen->br->binding_change = 1;
uloop_timeout_set(&udp_listen->br->utimer, 0);
save_udpcr_var_state(ip, port);
stun_notify(0);
}
else {
udp_listen->br = NULL;
}
}
goto end;
}
else if (strstr(resp_buf, "http") || strstr(resp_buf, "HTTP")) {
stun_log(SINFO, "get UDP Connection Request");
handle_udp_cr(resp_buf);
}
else {
stun_log(SINFO, "get non supported STUN/UDP message");
}
}
else {
/* timed out */
if (!udp_listen->br || udp_listen->br->resp_success == 1)
goto end;
stun_log(SINFO, "Timed OUT!");
udp_listen->br->resp_success--;
if (udp_listen->br->resp_success < -2) {
int rs = -udp_listen->br->resp_success;
if ((rs % 9) == 0) {
stun_log(SINFO, "Retry sending in a new socket");
stun_close_socket(udp_listen);
uloop_timeout_set(&udp_listen->br->utimer, 0);
udp_listen->br = NULL;
}
else if ((rs % 3) == 0) {
stun_log(SINFO, "Retry sending.");
uloop_timeout_set(&udp_listen->br->utimer, 0);
}
}
}
end:
uloop_timeout_set(timeout, 1);
}
int main()
{
stun_log(SINFO, "Start stund daemon");
config_init();
keepalive_timeout = conf.min_keepalive;
uloop_init();
uloop_timeout_set(&br_crport.utimer, 100);
uloop_run();
uloop_done();
config_fini();
stun_log(SINFO, "Stop stund daemon");
return 0;
}

106
stun/src/stun.h Normal file
View File

@@ -0,0 +1,106 @@
#ifndef _STUN_H
#define _STUN_H
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libubox/uloop.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#ifndef container_of
#define container_of(ptr, type, member) \
({ \
const typeof(((type *) NULL)->member) *__mptr = (ptr); \
(type *) ((char *) __mptr - offsetof(type, member)); \
})
#endif
#define binding_request_entry(X) container_of(X, struct binding_request, utimer)
#define udp_listen_entry(X) container_of(X, struct udp_listen, utimer)
#define BINDING_REQUSET 0x0001
#define BINDING_RESPONSE 0x0101
#define BINDING_ERROR 0x0111
#define ATTR_MAPPED_ADDRESS 0x0001
#define ATTR_RESPONSE_ADDRESS 0x0002
#define ATTR_CHANGE_REQUEST 0x0003
#define ATTR_SOURCE_ADDRESS 0x0004
#define ATTR_CHANGED_ADDRESS 0x0005
#define ATTR_USERNAME 0x0006
#define ATTR_PASSWORD 0x0007
#define ATTR_MESSAGE_INTEGRITY 0x0008
#define ATTR_ERROR_CODE 0x0009
#define ATTR_UNKNOWN_ATTRIBUTES 0x000a
#define ATTR_REFLECTED_FROM 0x000b
#define ATTR_CONNECTION_REQUEST_BINDING 0xC001
#define ATTR_BINDING_CHANGE 0xC002
#define STUN_HEADER_LEN 20
struct binding_request;
typedef struct { unsigned int id[4]; } __attribute__((packed)) stunid;
struct udp_listen {
stunid expected_id;
int fd;
struct uloop_timeout utimer;
struct binding_request *br;
};
struct binding_request {
stunid id;
unsigned char is_keealive;
unsigned char msg_integrity; /* if true ==> MESSAGE-INTEGRITY should be append in the STUN msg */
unsigned char binding_change; /* if true ==> BINDING-CHANGE should be append in the STUN msg */
unsigned char binding_cr; /* if true ==> CONNECTION-REQUEST-BINDING should be append in the STUN msg */
int resp_success;
int auth_fail;
int retry_interval;
struct udp_listen *udp_listen;
struct uloop_timeout utimer;
};
struct stun_header {
unsigned short type;
unsigned short len;
stunid id;
unsigned char stunmsg[0];
} __attribute__((packed));
struct stun_attribute {
unsigned short type;
unsigned short len;
unsigned char value[0];
} __attribute__((packed));
struct stun_address {
unsigned char na;
unsigned char family;
unsigned short port;
unsigned int address;
} __attribute__((packed));
struct env_var {
unsigned short port;
unsigned int address;
unsigned int last_ts;
unsigned int last_crid;
};
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif /* _STUN_H */

49
stun/src/stun.md Normal file
View File

@@ -0,0 +1,49 @@
# README #
In order to reach the devices that are connected behind NAT, the cwmp protocol introduces alternative method of executing Connection Request via NAT based on STUN. The stund is an implementation of STUN functionality that performs this feature.
## Configuration File ##
The stund UCI configuration is located in **'/etc/config/stun'** and contains only one section **stun**:
```
config stun 'stun'
option enable '0'
option username 'stun'
option password 'stun'
option server_address 'stun.l.google.com'
option server_port '19302'
option min_keepalive '30'
option max_keepalive '3600'
option client_port 7547
option log_level '1'
```
### stun section ###
It defines **the stun section configuration** (like username, password, etc...). The possible options for **stun** section are listed in the table below.
| Name | Type | Description |
| ---------------- | ------- | ------------------------------------------------- |
| `enable` | boolean | if set to **1**, the STUN client will be enabled. |
| `username` | string | The STUN username to be used in Binding Requests. |
| `password` | string | The STUN Password to be used in computing the MESSAGE-INTEGRITY. |
| `server_address` | string | The host name or IP address of the STUN server to send Binding Requests. |
| `server_port` | integer | The port number of the STUN server to send Binding Requests. |
| `min_keepalive` | integer | The minimum period that STUN Binding Requests must be sent by the CPE for the purpose of maintaining the binding in the Gateway. |
| `max_keepalive` | integer | The maximum period that STUN Binding Requests must be sent by the CPE for the purpose of maintaining the binding in the Gateway. |
| `client_port` | integer | The client source port of the STUN UDP binding. |
| `log_level` | integer | The log type to use, by default it is set to **'INFO'**. The possible types are **'EMERG', 'ALERT', 'CRITIC' ,'ERROR', 'WARNING', 'NOTICE', 'INFO' and 'DEBUG'**. |
## Dependencies ##
To successfully build stund, the following libraries are needed:
| Dependency | Link | License |
| --------------- | ------------------------------------------- | -------------- |
| libuci | https://git.openwrt.org/project/uci.git | LGPL 2.1 |
| libubox | https://git.openwrt.org/project/libubox.git | BSD |
| libubus | https://git.openwrt.org/project/ubus.git | LGPL 2.1 |
| libjson-c | https://s3.amazonaws.com/json-c_releases | MIT |
| libopenssl | http://ftp.fi.muni.cz/pub/openssl/source/ | OpenSSL |

108
stun/src/ubus.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* ubus.c -- This file conatains functions that allow to make ubus calls
*
*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <json-c/json.h>
#include <libubox/blobmsg_json.h>
#include <libubus.h>
#include "ubus.h"
static struct ubus_context *ubus_ctx = NULL;
static struct blob_buf b;
int subus_init(void)
{
ubus_ctx = ubus_connect(NULL);
if (!ubus_ctx) {
return -1;
}
return 0;
}
int subus_fini(void)
{
if (ubus_ctx) {
ubus_free(ubus_ctx);
}
ubus_ctx = NULL;
return 0;
}
void sadd_json_obj(json_object *json_obj_out, char *object, char *string)
{
json_object *json_obj_tmp = json_object_new_string(string);
json_object_object_add(json_obj_out, object, json_obj_tmp);
}
static int subus_call_req(char *path, char *method, int argc, struct sarg sarg[])
{
uint32_t id;
int i, r = 1;
char *arg;
json_object *json_obj_out = json_object_new_object();
if (json_obj_out == NULL)
return r;
blob_buf_init(&b, 0);
if (argc) {
for (i = 0; i < argc; i++) {
sadd_json_obj(json_obj_out, sarg[i].key, sarg[i].val);
}
arg = (char *)json_object_to_json_string(json_obj_out);
if (!blobmsg_add_json_from_string(&b, arg)) {
goto end;
}
}
if (ubus_lookup_id(ubus_ctx, path, &id))
goto end;
r = ubus_invoke(ubus_ctx, id, method, b.head, NULL, NULL, 1);
end:
json_object_put(json_obj_out);
blob_buf_free(&b);
return r;
}
int subus_call(char *path, char *method, int argc, struct sarg dmarg[])
{
int r = -1;
subus_init();
if (ubus_ctx) {
r = subus_call_req(path, method, argc, dmarg);
if (r > 0) r = -1;
}
subus_fini();
return r;
}

22
stun/src/ubus.h Normal file
View File

@@ -0,0 +1,22 @@
/* TR-069 STUN client software
* Copyright (C) 2020 PIVA SOFTWARE <www.pivasoftware.com> - All Rights Reserved
* Author: Omar Kallel <omar.kallel@pivasoftware.com>
*/
#ifndef __SUBUS_H
#define __SUBUS_H
#include <libubox/blobmsg_json.h>
#include <json-c/json.h>
#include <libubus.h>
struct sarg {
char *key;
char *val;
};
#define UBUS_ARGS (struct sarg[])
int subus_call(char *path, char *method, int argc, struct sarg sarg[]);
#endif //__SUBUS_H

44
twamp/Makefile Executable file
View File

@@ -0,0 +1,44 @@
#
# Copyright (C) 2020 iopsys Software Solutions AB
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=twamp
PKG_VERSION:=1.0.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=BBF twamp feature
DEPENDS:=+libuci +libbbf_api
endef
define Package/$(PKG_NAME)/description
BBF twamp feature
endef
define Build/Prepare
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += \
-D_GNU_SOURCE
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/twampd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/usr/lib/bbfdm
$(INSTALL_BIN) $(PKG_BUILD_DIR)/*.so $(1)/usr/lib/bbfdm
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -0,0 +1,13 @@
config twamp 'twamp'
option id '1'
#Log levels: Critical=0, Warning=1, Notice=2, Info=3, Debug=4
option log_level '3'
config twamp_reflector
option id '1'
option enable '0'
option interface 'lan'
option port '862'
option max_ttl '1'

56
twamp/files/etc/init.d/twampd Executable file
View File

@@ -0,0 +1,56 @@
#!/bin/sh /etc/rc.common
#TWAMP Reflector software
# Copyright (C) 2020 iopsys Software Solutions AB
#Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
START=99
STOP=10
USE_PROCD=1
PROG="/usr/sbin/twampd"
start_service() {
local id=`uci -q get twamp.twamp.id`
local connection=`uci show twamp | grep "twamp.@twamp_reflector.*id=\'$id\'" | cut -d "." -f 2`
local enable=`uci -q get twamp.$connection.enable`
local interface=`uci -q get twamp.$connection.interface`
local port=`uci -q get twamp.$connection.port`
local port_list=`uci -q get 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 twamp
}

23
twamp/src/Makefile Normal file
View File

@@ -0,0 +1,23 @@
PROG = twampd
LIB = libtwamp.so
PROG_OBJS = twamp.o twamplog.o twampuci.o twamptimestamp.o
LIB_OBJS = datamodel.o
PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC
PROG_LDFLAGS = $(LDFLAGS) -luci
LIB_LDFLAGS = $(LDFLAGS) -lbbf_api
%.o: %.c
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
all: $(PROG) $(LIB)
$(PROG): $(PROG_OBJS)
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
$(LIB): $(LIB_OBJS)
$(CC) $(PROG_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
clean:
rm -f *.o $(PROG) $(LIB)

309
twamp/src/datamodel.c Normal file
View File

@@ -0,0 +1,309 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <libbbf_api/dmbbf.h>
#include <libbbf_api/dmcommon.h>
#include <libbbf_api/dmuci.h>
#include <libbbf_api/dmubus.h>
#include <libbbf_api/dmjson.h>
#include "datamodel.h"
/* ********** RootDynamicObj ********** */
LIB_MAP_OBJ tRootDynamicObj[] = {
/* parentobj, nextobject */
{"Device.IP.Interface.", tDeviceTWAMPReflectorObj},
{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(inst, 4, s, opt_inst, package, section);
}
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;
}
struct ip_args
{
struct uci_section *ip_sec;
char *ip_4address;
};
static 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("twamp", "twamp_reflector", "interface", section_name(((struct ip_args *)data)->ip_sec), "twamp_inst");
id = get_last_id("twamp", "twamp_reflector");
dmuci_add_section("twamp", "twamp_reflector", &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;
}
static 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("twamp", "twamp_reflector", 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;
}
static 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;
}
static int set_IPInterfaceTWAMPReflector_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
bool b;
struct uci_section *s;
char *interface, *device, *id, *ipv4addr = "";
json_object *res, *jobj;
switch (action) {
case VALUECHECK:
if (dm_validate_boolean(value))
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("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);
}
dmuci_set_value_by_section((struct uci_section *)data, "device", get_device(interface));
} else {
dmuci_set_value_by_section((struct uci_section *)data, "enable", "0");
}
break;
}
return 0;
}
static 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;
}
static 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);
if ((*value)[0] == '\0')
dmasprintf(value, "cpe-%s", instance);
return 0;
}
static int set_IPInterfaceTWAMPReflector_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 64, NULL, 0, NULL, 0))
return FAULT_9007;
break;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "twamp_alias", value);
break;
}
return 0;
}
static 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;
}
static int set_IPInterfaceTWAMPReflector_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{NULL,"65535"}}, 1))
return FAULT_9007;
break;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "port", value);
break;
}
return 0;
}
static 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;
}
static int set_IPInterfaceTWAMPReflector_MaximumTTL(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"1","255"}}, 1))
return FAULT_9007;
break;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "max_ttl", value);
break;
}
return 0;
}
static 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;
}
static int set_IPInterfaceTWAMPReflector_IPAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string_list(value, -1, -1, 255, -1, -1, NULL, 0, NULL, 0))
return FAULT_9007;
break;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "ip_list", value);
break;
}
return 0;
}
static 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;
}
static int set_IPInterfaceTWAMPReflector_PortAllowedList(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string_list(value, -1, -1, 255, -1, -1, NULL, 0, NULL, 0))
return FAULT_9007;
break;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "port_list", value);
break;
}
return 0;
}
static int browseIPInterfaceTWAMPReflectorInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
struct uci_section *s = NULL;
char *inst = NULL, *max_inst = NULL;
uci_foreach_option_eq("twamp", "twamp_reflector", "interface", section_name(((struct ip_args *)prev_data)->ip_sec), s) {
inst = handle_update_instance(2, dmctx, &max_inst, update_instance_alias, 5,
s, "twamp_inst", "twamp_alias", "twamp", "twamp_reflector");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)s, inst) == DM_STOP)
break;
}
return 0;
}
/* *** Device.IP.Interface. *** */
DMOBJ tDeviceTWAMPReflectorObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"TWAMPReflector", &DMWRITE, addObjIPInterfaceTWAMPReflector, delObjIPInterfaceTWAMPReflector, NULL, browseIPInterfaceTWAMPReflectorInst, NULL, NULL, NULL, NULL, tIPInterfaceTWAMPReflectorParams, NULL, BBFDM_BOTH},
{0}
};
/* *** Device.IP.Interface.{i}.TWAMPReflector.{i}. *** */
DMLEAF tIPInterfaceTWAMPReflectorParams[] = {
/* PARAM, permission, type, getvalue, setvalue, forced_inform, notification, bbfdm_type*/
{"Enable", &DMWRITE, DMT_BOOL, get_IPInterfaceTWAMPReflector_Enable, set_IPInterfaceTWAMPReflector_Enable, NULL, NULL, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_IPInterfaceTWAMPReflector_Status, NULL, NULL, NULL, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_IPInterfaceTWAMPReflector_Alias, set_IPInterfaceTWAMPReflector_Alias, NULL, NULL, BBFDM_BOTH},
{"Port", &DMWRITE, DMT_UNINT, get_IPInterfaceTWAMPReflector_Port, set_IPInterfaceTWAMPReflector_Port, NULL, NULL, BBFDM_BOTH},
{"MaximumTTL", &DMWRITE, DMT_UNINT, get_IPInterfaceTWAMPReflector_MaximumTTL, set_IPInterfaceTWAMPReflector_MaximumTTL, NULL, NULL, BBFDM_BOTH},
{"IPAllowedList", &DMWRITE, DMT_STRING, get_IPInterfaceTWAMPReflector_IPAllowedList, set_IPInterfaceTWAMPReflector_IPAllowedList, NULL, NULL, BBFDM_BOTH},
{"PortAllowedList", &DMWRITE, DMT_STRING, get_IPInterfaceTWAMPReflector_PortAllowedList, set_IPInterfaceTWAMPReflector_PortAllowedList, NULL, NULL, BBFDM_BOTH},
{0}
};

17
twamp/src/datamodel.h Normal file
View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _TWAMP_H_
#define _TWAMP_H_
extern DMOBJ tDeviceTWAMPReflectorObj[];
extern DMLEAF tIPInterfaceTWAMPReflectorParams[];
#endif //_TWAMP_H_

858
twamp/src/twamp.c Normal file
View File

@@ -0,0 +1,858 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
* Name: Emma Mirică
* Project: TWAMP Protocol
* Class: OSS
* Email: emma.mirica@cti.pub.ro
* Contributions: stephanDB
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <time.h>
#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((uint32_t)sa.sin6_addr.s6_addr) & mask);
inet_pton(AF_INET6, ip, &(sa.sin6_addr));
maxaddress = (ntohl((uint32_t)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(&current, 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(&current, &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_reflector_option(char *instance, char *option)
{
struct uci_section *s;
char *v, *twamp_id;
dmuci_foreach_section("twamp", "twamp_reflector", 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, *value = NULL;
int a;
value = dmuci_get_value("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("twamp", "twamp", "id");
cur_twamp_conf.enable = atoi(get_twamp_reflector_option(id, "enable"));
cur_twamp_conf.interface = strdup(get_twamp_reflector_option(id, "interface"));
cur_twamp_conf.device = strdup(get_twamp_reflector_option(id, "device"));
cur_twamp_conf.ip_version = atoi(get_twamp_reflector_option(id, "ip_version"));
cur_twamp_conf.port = atoi(get_twamp_reflector_option(id, "port"));
cur_twamp_conf.max_ttl = atoi(get_twamp_reflector_option(id, "max_ttl"));
cur_twamp_conf.ip_list = strdup(get_twamp_reflector_option(id, "ip_list"));
cur_twamp_conf.port_list = strdup(get_twamp_reflector_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;
}

237
twamp/src/twamp.h Normal file
View File

@@ -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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
* 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 <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>
#include <sys/time.h>
#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__ */

57
twamp/src/twamp.md Normal file
View File

@@ -0,0 +1,57 @@
# README #
twampd is an implementation of the Two-Way Active Measurement Protocol (TWAMP) reflector.
## Configuration File ##
The twampd UCI configuration is located in **'/etc/config/twamp'**, and contains 2 sections the **twamp** and the **twamp\_reflector**.
```
config twamp 'twamp'
option id '1'
option log_level '3'
config twamp_reflector
option id '1'
option enable ''
option interface ''
option device ''
option ip_version ''
option port ''
option max_ttl ''
option ip_list ''
option port_list ''
```
### twamp section ###
It defines **the twamp configuration**: id, log_level. The possible options for **twamp** section are:
| Name | Type | Description |
| --------- | ------- | ------------------------------------------- |
| `id` | integer | Specifies the id of TWAMP reflector to use. |
| `log_level` | integer | Specifies the log type to use, by default **'INFO'**. The possible types are **'EMERG', 'ALERT', 'CRITIC' ,'ERROR', 'WARNING', 'NOTICE', 'INFO' and 'DEBUG'**. |
### twamp_reflector section ###
It describes **the twamp reflector configuration**: id, ip\_version, etc... The possible options for **twamp_reflector** section are:
| Name | Type | Description |
| ---------- | ------- | ------------------------------ |
| `id` | integer | Specifies the TWAMP id to use. |
| `enable` | boolean | If set to **1**, it enables the TWAMP reflector. |
| `ip_version` | integer | Specifies the IP version to use, **4** by default. The possible versions are **4** and **6**. |
| `port` | integer | Specifies the port to listen on. |
| `max_ttl` | integer | Specifies the maximum TTL of a received packet, that the TWAMP reflector will reflect to the TWAMP controller. |
| `ip_list` | string | Specifies the allowed source IP addresses and subnets to handle test packets. |
| `port_list` | string | Specifies the range of source ports allowed to use for twamp\_reflector tests. |
## Dependencies ##
To successfully build twampd, the following libraries are needed:
| Dependency | Link | License |
| ----------- | ------------------------------------------- | -------------- |
| libuci | https://git.openwrt.org/project/uci.git | LGPL 2.1 |

55
twamp/src/twamplog.c Normal file
View File

@@ -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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <stdio.h>
#include <time.h>
#include <syslog.h>
#include <stdarg.h>
#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;
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();
}
}

27
twamp/src/twamplog.h Normal file
View File

@@ -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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#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_ */

195
twamp/src/twamptimestamp.c Normal file
View File

@@ -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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
* Name: Emma Mirică
* Project: TWAMP Protocol
* Class: OSS
* Email: emma.mirica@cti.pub.ro
* Contributions: stephanDB
*
*/
#include <inttypes.h>
#include <sys/time.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <stdio.h>
#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
}

266
twamp/src/twampuci.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <uci.h>
#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)
{
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;
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];
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;
}

34
twamp/src/twampuci.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _TWAMPUCI_H__
#define _TWAMPUCI_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <uci.h>
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__ */

44
udpechoserver/Makefile Executable file
View File

@@ -0,0 +1,44 @@
#
# Copyright (C) 2020 iopsys Software Solutions AB
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=udpechoserver
PKG_VERSION:=1.0.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=BBF udp echo server
DEPENDS:=+libuci +libbbf_api
endef
define Package/$(PKG_NAME)/description
BBF UDP_echo_server
endef
define Build/Prepare
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += \
-D_GNU_SOURCE
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/udpechoserverd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/usr/lib/bbfdm
$(INSTALL_BIN) $(PKG_BUILD_DIR)/*.so $(1)/usr/lib/bbfdm
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -0,0 +1,10 @@
config udpechoserver 'udpechoserver'
option enable '0'
option interface ''
option address ''
option server_port '0'
option plus '0'
#Log levels: Critical=0, Warning=1, Notice=2, Info=3, Debug=4
option log_level '3'

View File

@@ -0,0 +1,39 @@
#!/bin/sh /etc/rc.common
#UDP Echo Server software
# Copyright (C) 2020 iopsys Software Solutions AB
#Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
START=99
STOP=10
USE_PROCD=1
PROG="/usr/sbin/udpechoserverd"
start_service() {
local enable_udpechoserver=`uci -q get udpechoserver.udpechoserver.enable`
local port_udpechoserver=`uci -q get udpechoserver.udpechoserver.server_port`
if [ "$port_udpechoserver" != "0" ]; then
if [ "$enable_udpechoserver" = "1" ]; then
iptables -I zone_wan_input -p udp --dport "$port_udpechoserver" -j ACCEPT -m comment --comment "Open UDPechoserver port"
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn "3" "7" "0"
procd_close_instance
else
iptables -I zone_wan_input -p udp --dport "$port_udpechoserver" -j REJECT -m comment --comment "Close UDPechoserver port"
fi
fi
}
boot() {
start
}
reload_service() {
stop
start
}
service_triggers() {
procd_add_reload_trigger udpechoserver
}

View File

@@ -0,0 +1,23 @@
PROG = udpechoserverd
LIB = libudpechoserver.so
PROG_OBJS = udpechoserver.o udpechoserverlog.o udpechoserveruci.o
LIB_OBJS = datamodel.o
PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC
PROG_LDFLAGS = $(LDFLAGS) -luci
LIB_LDFLAGS = $(LDFLAGS) -lbbf_api
%.o: %.c
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
all: $(PROG) $(LIB)
$(PROG): $(PROG_OBJS)
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
$(LIB): $(LIB_OBJS)
$(CC) $(PROG_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
clean:
rm -f *.o $(PROG) $(LIB)

View File

@@ -0,0 +1,213 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <libbbf_api/dmbbf.h>
#include <libbbf_api/dmcommon.h>
#include <libbbf_api/dmuci.h>
#include <libbbf_api/dmubus.h>
#include <libbbf_api/dmjson.h>
#include "datamodel.h"
/* ********** RootDynamicObj ********** */
LIB_MAP_OBJ tRootDynamicObj[] = {
/* parentobj, nextobject */
{"Device.IP.Diagnostics.", tDeviceUDPEchoConfigObj},
{0}
};
static int get_IPDiagnosticsUDPEchoConfig_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_option_value_string("udpechoserver", "udpechoserver", "enable", value);
return 0;
}
static int set_IPDiagnosticsUDPEchoConfig_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
bool b;
char file[32] = "/var/state/udpechoserver";
switch (action) {
case VALUECHECK:
if (dm_validate_boolean(value))
return FAULT_9007;
return 0;
case VALUESET:
string_to_bool(value, &b);
if (b) {
if( access( file, F_OK ) != -1 )
dmcmd("/bin/rm", 1, file);
dmuci_set_value("udpechoserver", "udpechoserver", "enable", "1");
} else
dmuci_set_value("udpechoserver", "udpechoserver", "enable", "0");
return 0;
}
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_option_value_string("udpechoserver", "udpechoserver", "interface", value);
return 0;
}
static int set_IPDiagnosticsUDPEchoConfig_Interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 256, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value("udpechoserver", "udpechoserver", "interface", value);
return 0;
}
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_SourceIPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_option_value_string("udpechoserver", "udpechoserver", "address", value);
return 0;
}
static int set_IPDiagnosticsUDPEchoConfig_SourceIPAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 45, NULL, 0, IPAddress, 2))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value("udpechoserver", "udpechoserver", "address", value);
return 0;
}
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_UDPPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_option_value_string("udpechoserver", "udpechoserver", "server_port", value);
return 0;
}
static int set_IPDiagnosticsUDPEchoConfig_UDPPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{NULL,NULL}}, 1))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value("udpechoserver", "udpechoserver", "server_port", value);
return 0;
}
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_EchoPlusEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_option_value_string("udpechoserver", "udpechoserver", "plus", value);
return 0;
}
static int set_IPDiagnosticsUDPEchoConfig_EchoPlusEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
bool b;
switch (action) {
case VALUECHECK:
if (dm_validate_boolean(value))
return FAULT_9007;
return 0;
case VALUESET:
string_to_bool(value, &b);
dmuci_set_value("udpechoserver", "udpechoserver", "plus", b ? "1" : "0");
return 0;
}
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_EchoPlusSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = "true";
return 0;
}
static inline char *udpechoconfig_get(char *option, char *def)
{
char *tmp;
dmuci_get_varstate_string("udpechoserver", "udpechoserver", option, &tmp);
if(tmp && tmp[0] == '\0')
return dmstrdup(def);
else
return tmp;
}
static int get_IPDiagnosticsUDPEchoConfig_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = udpechoconfig_get("PacketsReceived", "0");
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_PacketsResponded(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = udpechoconfig_get("PacketsResponded", "0");
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = udpechoconfig_get("BytesReceived", "0");
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_BytesResponded(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = udpechoconfig_get("BytesResponded", "0");
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_TimeFirstPacketReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = udpechoconfig_get("TimeFirstPacketReceived", "0");
return 0;
}
static int get_IPDiagnosticsUDPEchoConfig_TimeLastPacketReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = udpechoconfig_get("TimeLastPacketReceived", "0");
return 0;
}
/* *** Device.IP.Diagnostics. *** */
DMOBJ tDeviceUDPEchoConfigObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"UDPEchoConfig", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tIPDiagnosticsUDPEchoConfigParams, NULL, BBFDM_BOTH},
{0}
};
/* *** Device.IP.Diagnostics.UDPEchoConfig. *** */
DMLEAF tIPDiagnosticsUDPEchoConfigParams[] = {
/* PARAM, permission, type, getvalue, setvalue, forced_inform, notification, bbfdm_type*/
{"Enable", &DMWRITE, DMT_BOOL, get_IPDiagnosticsUDPEchoConfig_Enable, set_IPDiagnosticsUDPEchoConfig_Enable, NULL, NULL, BBFDM_BOTH},
{"Interface", &DMWRITE, DMT_STRING, get_IPDiagnosticsUDPEchoConfig_Interface, set_IPDiagnosticsUDPEchoConfig_Interface, NULL, NULL, BBFDM_BOTH},
{"SourceIPAddress", &DMWRITE, DMT_STRING, get_IPDiagnosticsUDPEchoConfig_SourceIPAddress, set_IPDiagnosticsUDPEchoConfig_SourceIPAddress, NULL, NULL, BBFDM_BOTH},
{"UDPPort", &DMWRITE, DMT_UNINT, get_IPDiagnosticsUDPEchoConfig_UDPPort, set_IPDiagnosticsUDPEchoConfig_UDPPort, NULL, NULL, BBFDM_BOTH},
{"EchoPlusEnabled", &DMWRITE, DMT_BOOL, get_IPDiagnosticsUDPEchoConfig_EchoPlusEnabled, set_IPDiagnosticsUDPEchoConfig_EchoPlusEnabled, NULL, NULL, BBFDM_BOTH},
{"EchoPlusSupported", &DMREAD, DMT_BOOL, get_IPDiagnosticsUDPEchoConfig_EchoPlusSupported, NULL, NULL, NULL, BBFDM_BOTH},
{"PacketsReceived", &DMREAD, DMT_UNINT, get_IPDiagnosticsUDPEchoConfig_PacketsReceived, NULL, NULL, NULL, BBFDM_BOTH},
{"PacketsResponded", &DMREAD, DMT_UNINT, get_IPDiagnosticsUDPEchoConfig_PacketsResponded, NULL, NULL, NULL, BBFDM_BOTH},
{"BytesReceived", &DMREAD, DMT_UNINT, get_IPDiagnosticsUDPEchoConfig_BytesReceived, NULL, NULL, NULL, BBFDM_BOTH},
{"BytesResponded", &DMREAD, DMT_UNINT, get_IPDiagnosticsUDPEchoConfig_BytesResponded, NULL, NULL, NULL, BBFDM_BOTH},
{"TimeFirstPacketReceived", &DMREAD, DMT_TIME, get_IPDiagnosticsUDPEchoConfig_TimeFirstPacketReceived, NULL, NULL, NULL, BBFDM_BOTH},
{"TimeLastPacketReceived", &DMREAD, DMT_TIME, get_IPDiagnosticsUDPEchoConfig_TimeLastPacketReceived, NULL, NULL, NULL, BBFDM_BOTH},
{0}
};

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _UDPECHOSERVER_H_
#define _UDPECHOSERVER_H_
extern DMOBJ tDeviceUDPEchoConfigObj[];
extern DMLEAF tIPDiagnosticsUDPEchoConfigParams[];
#endif //_UDPECHOSERVER_H_

View File

@@ -0,0 +1,230 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <netdb.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "udpechoserver.h"
#include "udpechoserverlog.h"
#include "udpechoserveruci.h"
struct udpechoserver_config cur_udpechoserver_conf = {0};
struct udpechoserver_result cur_udpechoserver_result={0};
static void set_udpechoserver_stats(void)
{
char PacketsReceived[8], PacketsResponded[8], BytesReceived[8], BytesResponded[8];
sprintf(PacketsReceived, "%d", cur_udpechoserver_result.PacketsReceived);
sprintf(PacketsResponded, "%d", cur_udpechoserver_result.PacketsResponded);
sprintf(BytesReceived, "%d", cur_udpechoserver_result.BytesReceived);
sprintf(BytesResponded, "%d", cur_udpechoserver_result.BytesResponded);
dmuci_init();
dmuci_set_value_state("udpechoserver", "udpechoserver", "PacketsReceived", PacketsReceived);
dmuci_set_value_state("udpechoserver", "udpechoserver", "PacketsResponded", PacketsResponded);
dmuci_set_value_state("udpechoserver", "udpechoserver", "BytesReceived", BytesReceived);
dmuci_set_value_state("udpechoserver", "udpechoserver", "BytesResponded", BytesResponded);
dmuci_set_value_state("udpechoserver", "udpechoserver", "TimeFirstPacketReceived", cur_udpechoserver_result.TimeFirstPacket);
dmuci_set_value_state("udpechoserver", "udpechoserver", "TimeLastPacketReceived", cur_udpechoserver_result.TimeLastPacket);
dmuci_fini();
}
int udpechoserver_connect(void)
{
int sock, fromlen, n, ret;
struct sockaddr_in server, from;
struct timeval tv_recv, tv_reply;
struct tm lt;
char buf[1024];
char str[INET_ADDRSTRLEN];
char s_now[default_date_size];
struct udpechoserver_plus *plus;
memset(&cur_udpechoserver_result, 0, sizeof(cur_udpechoserver_result));
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
udpechoserver_log(SCRIT,"Socket error = %d", sock);
return -1;
}
bzero(&server, sizeof(server));
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
server.sin_port=htons(cur_udpechoserver_conf.server_port);
if (bind(sock, (struct sockaddr *)&server, sizeof(server)) > 0) {
udpechoserver_log(SCRIT,"Error in bind function");
return -1;
}
udpechoserver_log(SINFO,"CONNECT UDPECHOSERVER");
while(true)
{
fromlen = sizeof(from);
n = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);
if (n < 0)
udpechoserver_log(SCRIT,"Error in receive message");
inet_ntop(AF_INET, &(from.sin_addr.s_addr), str, INET_ADDRSTRLEN);
udpechoserver_log(SINFO,"UDPECHOSERVER receive massage from %s with data size is %d Bytes", str, n);
if(cur_udpechoserver_conf.address && cur_udpechoserver_conf.address[0] != '\0') {
if(strcmp(cur_udpechoserver_conf.address, str) != 0) {
udpechoserver_log(SINFO,"UDPECHOSERVER can not respond to a UDP echo from this source IP address %s", str);
continue;
}
}
gettimeofday(&tv_recv, NULL);
if(cur_udpechoserver_result.TimeFirstPacketReceived.tv_sec == 0 && cur_udpechoserver_result.TimeFirstPacketReceived.tv_usec == 0)
cur_udpechoserver_result.TimeFirstPacketReceived = tv_recv;
cur_udpechoserver_result.TimeLastPacketReceived = tv_recv;
cur_udpechoserver_result.PacketsReceived++;
cur_udpechoserver_result.BytesReceived+=n;
(void) localtime_r(&(cur_udpechoserver_result.TimeFirstPacketReceived.tv_sec), &lt);
strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", &lt);
sprintf(cur_udpechoserver_result.TimeFirstPacket,"%s.%06ld", s_now, (long) cur_udpechoserver_result.TimeFirstPacketReceived.tv_usec);
(void) localtime_r(&(cur_udpechoserver_result.TimeLastPacketReceived.tv_sec), &lt);
strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", &lt);
sprintf(cur_udpechoserver_result.TimeLastPacket,"%s.%06ld", s_now, (long) cur_udpechoserver_result.TimeLastPacketReceived.tv_usec);
if(cur_udpechoserver_conf.plus) {
if(n >= sizeof(struct udpechoserver_plus)) {
plus = (struct udpechoserver_plus *)buf;
plus->TestRespSN = htonl(cur_udpechoserver_result.TestRespSN);
plus->TestRespRecvTimeStamp = htonl(tv_recv.tv_sec*1000000+tv_recv.tv_usec);
plus->TestRespReplyFailureCount = htonl(cur_udpechoserver_result.TestRespReplyFailureCount);
gettimeofday(&tv_reply, NULL);
plus->TestRespReplyTimeStamp = htonl(tv_reply.tv_sec*1000000+tv_reply.tv_usec);
}
}
ret = sendto(sock, buf, n, 0, (struct sockaddr *)&from, fromlen);
if (n != ret) {
cur_udpechoserver_result.TestRespReplyFailureCount++;
udpechoserver_log(SCRIT,"Error in send massage");
}
else {
cur_udpechoserver_result.TestRespSN++;
cur_udpechoserver_result.PacketsResponded++;
cur_udpechoserver_result.BytesResponded+=ret;
}
udpechoserver_log(SINFO,"UDPECHOSERVER sent massage to %s with data size is %d Bytes", str, ret);
set_udpechoserver_stats();
udpechoserver_log(SDEBUG,"UDPECHOSERVER Stats : PacketsReceived = %d", cur_udpechoserver_result.PacketsReceived);
udpechoserver_log(SDEBUG,"UDPECHOSERVER Stats : PacketsResponded = %d", cur_udpechoserver_result.PacketsResponded);
udpechoserver_log(SDEBUG,"UDPECHOSERVER Stats : BytesReceived = %d", cur_udpechoserver_result.BytesReceived);
udpechoserver_log(SDEBUG,"UDPECHOSERVER Stats : BytesResponded = %d", cur_udpechoserver_result.BytesResponded);
udpechoserver_log(SDEBUG,"UDPECHOSERVER Stats : TestRespReplyFailureCount = %d", cur_udpechoserver_result.TestRespReplyFailureCount);
udpechoserver_log(SDEBUG,"UDPECHOSERVER Stats : TimeFirstPacketReceived = %s", cur_udpechoserver_result.TimeFirstPacket);
udpechoserver_log(SDEBUG,"UDPECHOSERVER Stats : TimeLastPacketReceived = %s", cur_udpechoserver_result.TimeLastPacket);
}
}
int udpechoserver_init(void)
{
char *value = NULL;
int a;
value = dmuci_get_value("udpechoserver", "udpechoserver", "log_level");
if(value != NULL && *value != '\0') {
a = atoi(value);
cur_udpechoserver_conf.loglevel = a;
}
else
cur_udpechoserver_conf.loglevel = DEFAULT_LOGLEVEL;
udpechoserver_log(SDEBUG,"Log Level of UDP ECHO SERVER is :%d", cur_udpechoserver_conf.loglevel);
value = dmuci_get_value("udpechoserver", "udpechoserver", "enable");
if(value != NULL && *value != '\0') {
if ((strcasecmp(value,"true")==0) || (strcmp(value,"1")==0)) {
cur_udpechoserver_conf.enable = true;
udpechoserver_log(SDEBUG,"UDP echo server is Enabled");
}
}
value = dmuci_get_value("udpechoserver", "udpechoserver", "interface");
if(value != NULL && *value != '\0') {
if (cur_udpechoserver_conf.interface != NULL)
free(cur_udpechoserver_conf.interface);
cur_udpechoserver_conf.interface = strdup(value);
udpechoserver_log(SDEBUG,"UDP echo server interface is :%s", cur_udpechoserver_conf.interface);
}
else {
cur_udpechoserver_conf.interface = strdup("");
udpechoserver_log(SDEBUG,"UDP echo server interface is empty");
}
value = dmuci_get_value("udpechoserver", "udpechoserver", "address");
if(value != NULL && *value != '\0') {
if (cur_udpechoserver_conf.address != NULL)
free(cur_udpechoserver_conf.address);
cur_udpechoserver_conf.address = strdup(value);
udpechoserver_log(SDEBUG,"UDP echo server address is :%s", cur_udpechoserver_conf.address);
}
else {
cur_udpechoserver_conf.address = strdup("");
udpechoserver_log(SDEBUG,"UDP echo server address is empty");
}
value = dmuci_get_value("udpechoserver", "udpechoserver", "server_port");
if(value != NULL && *value != '\0') {
a = atoi(value);
cur_udpechoserver_conf.server_port = a;
udpechoserver_log(SDEBUG,"UDP echo server port is :%d", cur_udpechoserver_conf.server_port);
}
value = dmuci_get_value("udpechoserver", "udpechoserver", "plus");
if(value != NULL && *value != '\0') {
if ((strcasecmp(value,"true")==0) || (strcmp(value,"1")==0)) {
cur_udpechoserver_conf.plus = true;
udpechoserver_log(SDEBUG,"UDP echo server plus is Enabled");
}
else {
cur_udpechoserver_conf.plus = false;
udpechoserver_log(SDEBUG,"UDP echo server plus is Disabled");
}
}
return 0;
}
void udpechoserver_exit(void)
{
free(cur_udpechoserver_conf.address);
free(cur_udpechoserver_conf.interface);
}
int main(void)
{
dmuci_init();
udpechoserver_init();
dmuci_fini();
udpechoserver_log(SINFO,"START UDPECHOSERVER");
udpechoserver_connect();
udpechoserver_exit();
udpechoserver_log(SINFO,"EXIT UDPECHOSERVER");
return 0;
}

View File

@@ -0,0 +1,56 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _UDPECHOSERVER_H__
#define _UDPECHOSERVER_H__
#include <stdbool.h>
#include <sys/time.h>
#define default_date_format "AAAA-MM-JJTHH:MM:SS.000000Z"
#define default_date_size sizeof(default_date_format) + 1
struct udpechoserver_config
{
bool enable;
char *interface;
char *address;
int server_port;
bool plus;
int loglevel;
};
struct udpechoserver_plus
{
unsigned int TestGenSN;
unsigned int TestRespSN;
unsigned int TestRespRecvTimeStamp;
unsigned int TestRespReplyTimeStamp;
unsigned int TestRespReplyFailureCount;
};
struct udpechoserver_result
{
unsigned int TestRespSN;
unsigned int TestRespReplyFailureCount;
unsigned int PacketsReceived;
unsigned int PacketsResponded;
unsigned int BytesReceived;
unsigned int BytesResponded;
struct timeval TimeFirstPacketReceived;
struct timeval TimeLastPacketReceived;
char TimeFirstPacket[default_date_size];
char TimeLastPacket[default_date_size];
};
extern struct udpechoserver_config cur_udpechoserver_conf;
extern struct udpechoserver_result cur_udpechoserver_result;
#endif /* _UDPECHOSERVER_H__ */

View File

@@ -0,0 +1,40 @@
# README #
udpechoserverd is an implementation of udp echo server to perform the UDP Echo Service and UDP Echo Plus Service.
## Configuration File ##
The udpechoserverd UCI configuration is located in **'/etc/config/udpechoserver'** and contains only one section: **udpechoserver**.
```
config udpechoserver 'udpechoserver'
option enable '0'
option interface ''
option address ''
option server_port ''
option plus '0'
option log_level '3'
```
### udpechoserver section ###
It defines **the udpechoserver configuration** such as enable, interface, address, etc... Possible options to be used in **the udpechoserver** section are listed in the table below.
| Name | Type | Description |
| ------------- | ------- | ------------------------------------------------- |
| `enable` | boolean | If set to **1**, UDP Echo Server will be enabled. |
| `interface` | string | Specifies the interface on which the CPE MUST listen and receive UDP echo requests. |
| `address` | string | Specifies the source IP address which can make an UDP echo requests. |
| `server_port` | integer | The UDP port on which the UDP Echo server MUST listen and respond to UDP echo requests. |
| `plus` | boolean | If set to **1**, the CPE will perform necessary packet processing for UDP Echo Plus packets. |
| `log_level` | integer | Specifies the log type to use, by default it is set to **'INFO'**. The possible types are **'EMERG', 'ALERT', 'CRITIC' ,'ERROR', 'WARNING', 'NOTICE', 'INFO' and 'DEBUG'**. |
## Dependencies ##
To successfully build udpechoserverd, the following libraries are needed:
| Dependency | Link | License |
| ----------- | ------------------------------------------- | -------------- |
| libuci | https://git.openwrt.org/project/uci.git | LGPL 2.1 |

View File

@@ -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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <stdio.h>
#include <time.h>
#include <syslog.h>
#include <stdarg.h>
#include "udpechoserverlog.h"
#include "udpechoserver.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 udpechoserver_log(int priority, const char *format, ...)
{
va_list vl;
if (priority <= cur_udpechoserver_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 [udpechoserver] %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("udpechoserver", 0, LOG_DAEMON);
va_start(vl, format);
vsyslog(log_syslogmap[priority], format, vl);
va_end(vl);
closelog();
}
}

View File

@@ -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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _UDPECHOSERVERLOG_H_
#define _UDPECHOSERVERLOG_H_
#define DEFAULT_LOGLEVEL SINFO
enum udpechoserver_log_level_enum {
SCRIT,
SWARNING,
SNOTICE,
SINFO,
SDEBUG,
__MAX_SLOG
};
void udpechoserver_log(int priority, const char *format, ...);
#endif /* _UDPECHOSERVERLOG_H_ */

View File

@@ -0,0 +1,182 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <string.h>
#include <ctype.h>
#include <uci.h>
#include "udpechoserveruci.h"
static struct uci_context *uci_ctx = NULL;
static struct uci_context *uci_ctx_state = NULL;
int dmuci_init(void)
{
uci_ctx = uci_alloc_context();
if (!uci_ctx) {
return -1;
}
uci_ctx_state = uci_alloc_context();
if (!uci_ctx_state) {
return -1;
}
uci_add_delta_path(uci_ctx_state, uci_ctx_state->savedir);
uci_set_savedir(uci_ctx_state, VAR_STATE);
return 0;
}
int dmuci_fini(void)
{
if (uci_ctx) {
uci_free_context(uci_ctx);
}
if (uci_ctx_state) {
uci_free_context(uci_ctx_state);
}
uci_ctx = NULL;
uci_ctx_state = NULL;
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)
{
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;
}
void dmuci_print_list(struct uci_list *uh, char **val, char *delimiter)
{
struct uci_element *e;
static char buffer[512];
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;
}
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;
}
char *dmuci_set_value(char *package, char *section, char *option, char *value)
{
struct uci_ptr ptr;
int ret = UCI_OK;
if (!section)
return "";
if (dmuci_init_ptr(uci_ctx, &ptr, package, section, option, value)) {
return "";
}
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK) {
return "";
}
uci_set(uci_ctx, &ptr);
if (ret == UCI_OK)
ret = uci_save(uci_ctx, ptr.p);
if (ptr.o && ptr.o->v.string)
return ptr.o->v.string;
return "";
}
/************************* /var/state ***************************/
char *dmuci_set_value_state(char *package, char *section, char *option, char *value)
{
char *val;
struct uci_context *save_uci_ctx = uci_ctx;
uci_ctx = uci_ctx_state;
val = dmuci_set_value(package, section, option, value);
uci_ctx = save_uci_ctx;
return val;
}

View File

@@ -0,0 +1,25 @@
/*
* 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) 2020 iopsys Software Solutions AB
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _UDPECHOSERVERUCI_H__
#define _UDPECHOSERVERUCI_H__
#include <uci.h>
#define VAR_STATE "/var/state"
int dmuci_init(void);
int dmuci_fini(void);
void dmuci_print_list(struct uci_list *uh, char **val, char *delimiter);
char *dmuci_get_value(char *package, char *section, char *option);
char *dmuci_set_value(char *package, char *section, char *option, char *value);
char *dmuci_set_value_state(char *package, char *section, char *option, char *value);
#endif /* _UDPECHOSERVERUCI_H__ */

View File

@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=uspd
PKG_VERSION:=2.0.3
PKG_VERSION:=2.0.6
LOCAL_DEV:=0
ifneq ($(LOCAL_DEV),1)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=8045528fcfd44216b357fe671acc40847866bdc4
PKG_SOURCE_VERSION:=f4cb4407c275befee87cf761a51687d3b9869e99
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/uspd.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz
endif

View File

@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=wfadatad
PKG_VERSION:=2.2.2
PKG_VERSION:=2.3.0
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=b6d42b7459248e9fbbce9d828f50360e67bfe6c6
PKG_SOURCE_VERSION:=26701fdc83440a748aeff183bad2f67287764fb4
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/wfadatad.git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz

View File

@@ -6,6 +6,10 @@ STOP=11
USE_PROCD=1
PROG=/usr/sbin/wfadatad
service_running() {
ubus -t 2 wait_for ieee1905
}
start_service() {
procd_open_instance
procd_set_param command ${PROG}

View File

@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=wifimngr
PKG_VERSION:=7.8.0
PKG_VERSION:=8.2.9
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=a87fb7c82800d4d731205eee2ff956886353c086
PKG_SOURCE_VERSION:=ff879d814caba6807f64288de22db6f78c03438c
PKG_SOURCE_URL:=https://dev.iopsys.eu/iopsys/wifimngr.git
PKG_MAINTAINER:=Anjan Chanda <anjan.chanda@iopsys.eu>

44
xmpp/Makefile Executable file
View File

@@ -0,0 +1,44 @@
#
# Copyright (C) 2020 iopsys Software Solutions AB
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=xmpp
PKG_VERSION:=1.0.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=TRx69
TITLE:=BBF xmpp Client
DEPENDS:=+libuci +libubox +libstrophe +libbbf_api
endef
define Package/$(PKG_NAME)/description
BBF XMPP Client
endef
define Build/Prepare
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
TARGET_CFLAGS += \
-D_GNU_SOURCE
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/xmppd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/usr/lib/bbfdm
$(INSTALL_BIN) $(PKG_BUILD_DIR)/*.so $(1)/usr/lib/bbfdm
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -0,0 +1,29 @@
config xmpp 'xmpp'
option enable '0'
option id '0'
option allowed_jid ''
#Log levels: Critical=0, Warning=1, Notice=2, Info=3, Debug=4
option loglevel '3'
config connection
option xmpp_id '1'
option enable '0'
option username ''
option password ''
option domain ''
option resource ''
option usetls '0'
option interval '30'
option attempt '16'
option initial_retry_interval '1'
option retry_interval_multiplier '1000'
option retry_max_interval '1'
option serveralgorithm 'DNS-SRV'
config connection_server
option con_id '1'
option enable '0'
option port '5222'
option server_address ''

View File

@@ -1,6 +1,6 @@
#!/bin/sh
[ -f /etc/config/cwmp_xmpp ] || exit 0
[ -f /etc/config/xmpp ] || exit 0
[ "$ACTION" == "ifup" ] || exit 0
[ "$INTERFACE" == "loopback" ] && exit 0
@@ -17,5 +17,5 @@ local proto="$(uci -q get network.$INTERFACE.proto)"
local ifname="$(uci -q get network.$INTERFACE.ifname)"
[ "${ifname:0:1}" == "@" ] && exit 0
/etc/init.d/icwmp_xmppd reload &
/etc/init.d/xmppd reload &

42
xmpp/files/etc/init.d/xmppd Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/sh /etc/rc.common
# XMPP client software
# Copyright (C) 2020 iopsys Software Solutions AB
# Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
START=99
STOP=10
USE_PROCD=1
PROG="/usr/sbin/xmppd"
start_service() {
local xmpp_enable=`uci -q get xmpp.xmpp.enable`
local xmpp_id=`uci -q get xmpp.xmpp.id`
if ([ "$xmpp_enable" = "1" ] && [ "$xmpp_id" != "0" ]); then
local con=`uci show xmpp | grep "xmpp.@connection.*xmpp_id=\'$xmpp_id\'" | cut -d "." -f 2`
local con_srv=`uci show xmpp | grep "xmpp.@connection.*con_id=\'$xmpp_id\'" | cut -d "." -f 2`
local serveralgorithm=`uci get xmpp.$con.serveralgorithm`
local con_enable=`uci -q get xmpp.$con.enable`
local srv_enable=`uci -q get xmpp.$con_srv.enable`
if ([ "$serveralgorithm" = "DNS-SRV" ] && [ "$con_enable" = "1" ]) || ([ "$serveralgorithm" = "ServerTable" ] && [ "$con_enable" = "1" ] && [ "$srv_enable" = "1" ]); then
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn "3" "7" "0"
procd_close_instance
fi
fi
}
boot() {
start
}
reload_service() {
stop
start
}
service_triggers()
{
procd_add_reload_trigger xmpp
}

23
xmpp/src/Makefile Normal file
View File

@@ -0,0 +1,23 @@
PROG = xmppd
LIB = libxmpp.so
PROG_OBJS = xmpp.o xuci.o cmd.o log.o
LIB_OBJS = datamodel.o
PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC
PROG_LDFLAGS = $(LDFLAGS) -luci -lubox -lstrophe
LIB_LDFLAGS = $(LDFLAGS) -lbbf_api
%.o: %.c
$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
all: $(PROG) $(LIB)
$(PROG): $(PROG_OBJS)
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
$(LIB): $(LIB_OBJS)
$(CC) $(PROG_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ $^
clean:
rm -f *.o $(PROG) $(LIB)

78
xmpp/src/cmd.c Normal file
View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
static int pfds[2];
int xmpp_cmd(unsigned char dowait, int argc, ...)
{
int pid;
va_list arg;
if (pipe(pfds) < 0)
return -1;
if ((pid = fork()) == -1)
return -1;
if (pid == 0) {
/* child */
int i;
const char *argv[64];
va_start(arg, argc);
for (i = 0; i < argc; i++)
{
argv[i] = va_arg(arg, char *);
}
argv[i] = NULL;
va_end(arg);
close(pfds[0]);
dup2(pfds[1], 1);
close(pfds[1]);
execvp(argv[0], (char **) argv);
exit(ESRCH);
} else if (pid < 0)
return -1;
/* parent */
close(pfds[1]);
if (dowait) {
int status;
while (wait(&status) != pid);
}
return 0;
}
void xmpp_cmd_close(void)
{
close(pfds[0]);
}

34
xmpp/src/cmd.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef __XMPPCMD_H
#define __XMPPCMD_H
int xmpp_cmd(unsigned char wait, int argc, ...);
void xmpp_cmd_close(void);
#define XMPP_CMD(ARGC, args...) \
do { \
xmpp_cmd(1, ARGC, ##args); \
xmpp_cmd_close(); \
} while(0)
#endif //__XMPPCMD_H

647
xmpp/src/datamodel.c Normal file
View File

@@ -0,0 +1,647 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#include <libbbf_api/dmbbf.h>
#include <libbbf_api/dmcommon.h>
#include <libbbf_api/dmuci.h>
#include <libbbf_api/dmubus.h>
#include <libbbf_api/dmjson.h>
#include "datamodel.h"
/* ********** RootDynamicObj ********** */
LIB_MAP_OBJ tRootDynamicObj[] = {
/* parentobj, nextobject */
{"Device.", tDeviceXMPPObj},
{0}
};
static int add_xmpp_connection(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
struct uci_section *xmpp_con, *xmpp_con_srv, *dmmap_xmpp;
char *con_name, *con_srv_name, *last_inst, *v, *id;
check_create_dmmap_package("dmmap_xmpp");
last_inst = get_last_instance_bbfdm("dmmap_xmpp", "connection", "con_inst");
dmasprintf(&id, "%d", (last_inst) ? atoi(last_inst) + 1 : 1);
dmuci_add_section_and_rename("xmpp", "connection", &xmpp_con, &con_name);
dmuci_set_value_by_section(xmpp_con, "xmpp_id", id);
dmuci_set_value_by_section(xmpp_con, "enable", "0");
dmuci_set_value_by_section(xmpp_con, "interval", "30");
dmuci_set_value_by_section(xmpp_con, "attempt", "16");
dmuci_set_value_by_section(xmpp_con, "serveralgorithm", "DNS-SRV");
dmuci_add_section_and_rename("xmpp", "connection_server", &xmpp_con_srv, &con_srv_name);
dmuci_set_value_by_section(xmpp_con_srv, "con_id", id);
dmuci_set_value_by_section(xmpp_con_srv, "enable", "0");
dmuci_set_value_by_section(xmpp_con_srv, "port", "5222");
dmuci_add_section_bbfdm("dmmap_xmpp", "connection_server", &dmmap_xmpp, &v);
dmuci_set_value_by_section(dmmap_xmpp, "section_name", section_name(xmpp_con_srv));
dmuci_set_value_by_section(dmmap_xmpp, "con_srv_inst", "1");
dmuci_add_section_bbfdm("dmmap_xmpp", "connection", &dmmap_xmpp, &v);
dmuci_set_value_by_section(dmmap_xmpp, "section_name", section_name(xmpp_con));
*instance = update_instance(last_inst, 4, dmmap_xmpp, "con_inst", "dmmap_xmpp", "connection");
return 0;
}
static int delete_xmpp_connection(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
struct uci_section *s = NULL, *ss = NULL, *dmmap_section = NULL, *stmp = NULL;
char *prev_con_id;
int found = 0;
switch (del_action) {
case DEL_INST:
dmuci_get_value_by_section_string((struct uci_section *)data, "xmpp_id", &prev_con_id);
uci_foreach_option_eq_safe("xmpp", "connection_server", "con_id", prev_con_id, stmp, s) {
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name(s), &dmmap_section);
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section(s, NULL, NULL);
break;
}
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name((struct uci_section *)data), &dmmap_section);
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section((struct uci_section *)data, NULL, NULL);
return 0;
case DEL_ALL:
uci_foreach_sections("xmpp", "connection", s) {
if (found != 0) {
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name(ss), &dmmap_section);
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section(ss, NULL, NULL);
}
ss = s;
found++;
}
if (ss != NULL) {
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name(ss), &dmmap_section);
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section(ss, NULL, NULL);
}
found = 0;
uci_foreach_sections("xmpp", "connection_server", s) {
if (found != 0) {
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name(ss), &dmmap_section);
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section(ss, NULL, NULL);
}
ss = s;
found++;
}
if (ss != NULL) {
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name(ss), &dmmap_section);
dmuci_delete_by_section(dmmap_section, NULL, NULL);
dmuci_delete_by_section(ss, NULL, NULL);
}
return 0;
}
return 0;
}
/*#Device.XMPP.ConnectionNumberOfEntries!UCI:xmpp/xmpp_connection/*/
static int get_xmpp_connection_nbr_entry(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
struct uci_section *s;
int cnt = 0;
uci_foreach_sections("xmpp", "connection", s) {
cnt++;
}
dmasprintf(value, "%d", cnt); // MEM WILL BE FREED IN DMMEMCLEAN
return 0;
}
static int get_xmpp_connection_supported_server_connect_algorithms(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = "DNS-SRV,ServerTable";
return 0;
}
/*#Device.XMPP.Connection.{i}.Enable!UCI:xmpp/xmpp_connection,@i-1/enable*/
static int get_connection_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;
}
static int set_connection_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
bool b;
switch (action) {
case VALUECHECK:
if (dm_validate_boolean(value))
return FAULT_9007;
return 0;
case VALUESET:
string_to_bool(value, &b);
dmuci_set_value_by_section((struct uci_section *)data, "enable", b ? "1" : "0");
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Alias!UCI:dmmap_xmpp/connection,@i-1/con_alias*/
static int get_xmpp_connection_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
struct uci_section *dmmap_section = NULL;
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name((struct uci_section *)data), &dmmap_section);
dmuci_get_value_by_section_string(dmmap_section, "con_alias", value);
if ((*value)[0] == '\0')
dmasprintf(value, "cpe-%s", instance);
return 0;
}
static int set_xmpp_connection_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
struct uci_section *dmmap_section = NULL;
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 64, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
get_dmmap_section_of_config_section("dmmap_xmpp", "connection", section_name((struct uci_section *)data), &dmmap_section);
dmuci_set_value_by_section(dmmap_section, "con_alias", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Username!UCI:xmpp/xmpp_connection,@i-1/username*/
static int get_xmpp_connection_username(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "username", value);
return 0;
}
static int set_xmpp_connection_username(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 256, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "username", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Password!UCI:xmpp/xmpp_connection,@i-1/password*/
static int get_xmpp_connection_password(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = "";
return 0;
}
static int set_xmpp_connection_password(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 256, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "password", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Domain!UCI:xmpp/xmpp_connection,@i-1/domain*/
static int get_xmpp_connection_domain(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "domain", value);
return 0;
}
static int set_xmpp_connection_domain(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 64, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "domain", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Resource!UCI:xmpp/xmpp_connection,@i-1/resource*/
static int get_xmpp_connection_resource(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "resource", value);
return 0;
}
static int set_xmpp_connection_resource(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 64, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "resource", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.ServerConnectAlgorithm!UCI:xmpp/xmpp_connection,@i-1/serveralgorithm*/
static int get_xmpp_connection_server_connect_algorithm(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "serveralgorithm", value);
return 0;
}
static int set_xmpp_connection_server_connect_algorithm(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, -1, ServerConnectAlgorithm, 4, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "serveralgorithm", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.KeepAliveInterval!UCI:xmpp/xmpp_connection,@i-1/interval*/
static int get_xmpp_connection_keepalive_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "interval", value);
return 0;
}
static int set_xmpp_connection_keepalive_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_long(value, RANGE_ARGS{{"-1",NULL}}, 1))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "interval", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.ServerConnectAttempts!UCI:xmpp/xmpp_connection,@i-1/attempt*/
static int get_xmpp_connection_server_attempts(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "attempt", value);
return 0;
}
static int set_xmpp_connection_server_attempts(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{NULL,NULL}}, 1))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "attempt", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.ServerRetryInitialInterval!UCI:xmpp/xmpp_connection,@i-1/initial_retry_interval*/
static int get_xmpp_connection_retry_initial_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "initial_retry_interval", value);
return 0;
}
static int set_xmpp_connection_retry_initial_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"1","65535"}}, 1))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "initial_retry_interval", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.ServerRetryIntervalMultiplier!UCI:xmpp/xmpp_connection,@i-1/retry_interval_multiplier*/
static int get_xmpp_connection_retry_interval_multiplier(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "retry_interval_multiplier", value);
return 0;
}
static int set_xmpp_connection_retry_interval_multiplier(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"1000","65535"}}, 1))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "retry_interval_multiplier", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.ServerRetryMaxInterval!UCI:xmpp/xmpp_connection,@i-1/retry_max_interval*/
static int get_xmpp_connection_retry_max_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "retry_max_interval", value);
return 0;
}
static int set_xmpp_connection_retry_max_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"1",NULL}}, 1))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "retry_max_interval", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.UseTLS!UCI:xmpp/xmpp_connection,@i-1/usetls*/
static int get_xmpp_connection_server_usetls(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "usetls", value);
return 0;
}
static int set_xmpp_connection_server_usetls(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
bool b;
switch (action) {
case VALUECHECK:
if (dm_validate_boolean(value))
return FAULT_9007;
return 0;
case VALUESET:
string_to_bool(value, &b);
dmuci_set_value_by_section((struct uci_section *)data, "usetls", b ? "1" : "0");
return 0;
}
return 0;
}
static int get_xmpp_connection_jabber_id(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
char *resource, *domain, *username;
dmuci_get_value_by_section_string((struct uci_section *)data, "resource", &resource);
dmuci_get_value_by_section_string((struct uci_section *)data, "domain", &domain);
dmuci_get_value_by_section_string((struct uci_section *)data, "username", &username);
if (*resource != '\0' || *domain != '\0' || *username != '\0')
dmasprintf(value, "%s@%s/%s", username, domain, resource);
else
*value = "";
return 0;
}
/*#Device.XMPP.Connection.{i}.Status!UCI:xmpp/xmpp_connection,@i-1/enable*/
static int get_xmpp_connection_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
char *status;
dmuci_get_value_by_section_string((struct uci_section *)data, "enable", &status);
*value = (strcmp(status, "1") == 0) ? "Enabled" : "Disabled";
return 0;
}
static int get_xmpp_connection_server_number_of_entries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
*value = "1";
return 0;
}
/*#Device.XMPP.Connection.{i}.Server.{i}.Enable!UCI:xmpp/xmpp_connection,@i-1/enable*/
static int get_xmpp_connection_server_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;
}
static int set_xmpp_connection_server_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
bool b;
switch (action) {
case VALUECHECK:
if (dm_validate_boolean(value))
return FAULT_9007;
return 0;
case VALUESET:
string_to_bool(value, &b);
dmuci_set_value_by_section((struct uci_section *)data, "enable", b ? "1" : "0");
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Server.{i}.Alias!UCI:dmmap_xmpp/connection_server,@i-1/con_srv_alias*/
static int get_xmpp_connection_server_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
struct uci_section *dmmap_section = NULL;
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name((struct uci_section *)data), &dmmap_section);
dmuci_get_value_by_section_string(dmmap_section, "con_srv_alias", value);
if ((*value)[0] == '\0')
dmasprintf(value, "cpe-%s", instance);
return 0;
}
static int set_xmpp_connection_server_alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
struct uci_section *dmmap_section = NULL;
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 64, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
get_dmmap_section_of_config_section("dmmap_xmpp", "connection_server", section_name((struct uci_section *)data), &dmmap_section);
dmuci_set_value_by_section(dmmap_section, "con_srv_alias", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Server.{i}.ServerAddress!UCI:xmpp/xmpp_connection,@i-1/server_address*/
static int get_xmpp_connection_server_server_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
dmuci_get_value_by_section_string((struct uci_section *)data, "server_address", value);
return 0;
}
static int set_xmpp_connection_server_server_address(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_string(value, -1, 256, NULL, 0, NULL, 0))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "server_address", value);
return 0;
}
return 0;
}
/*#Device.XMPP.Connection.{i}.Server.{i}.Port!UCI:xmpp/xmpp_connection,@i-1/port*/
static int get_xmpp_connection_server_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;
}
static int set_xmpp_connection_server_port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
switch (action) {
case VALUECHECK:
if (dm_validate_unsignedInt(value, RANGE_ARGS{{"0","65535"}}, 1))
return FAULT_9007;
return 0;
case VALUESET:
dmuci_set_value_by_section((struct uci_section *)data, "port", value);
return 0;
}
return 0;
}
/*************************************************************
* ENTRY METHOD
**************************************************************/
/*#Device.XMPP.Connection.{i}.!UCI:xmpp/xmpp_connection/dmmap_cwmp_xmpp*/
static int browsexmpp_connectionInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
char *inst, *max_inst = NULL;
struct dmmap_dup *p;
LIST_HEAD(dup_list);
synchronize_specific_config_sections_with_dmmap("xmpp", "connection", "dmmap_xmpp", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_update_instance(1, dmctx, &max_inst, update_instance_alias, 5,
p->dmmap_section, "con_inst", "con_alias", "dmmap_xmpp", "connection");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
break;
}
free_dmmap_config_dup_list(&dup_list);
return 0;
}
/*#Device.XMPP.Connection.{i}.!UCI:xmpp/xmpp_connection_server/dmmap_cwmp_xmpp*/
static int browsexmpp_connection_serverInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
char *inst, *max_inst = NULL, *con_id;
struct dmmap_dup *p;
LIST_HEAD(dup_list);
dmuci_get_value_by_section_string((struct uci_section *)prev_data, "xmpp_id", &con_id);
synchronize_specific_config_sections_with_dmmap_eq("xmpp", "connection_server", "dmmap_xmpp", "con_id", con_id, &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_update_instance(2, dmctx, &max_inst, update_instance_alias, 5,
p->dmmap_section, "con_srv_inst", "con_srv_alias", "xmpp", "connection_server");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
break;
}
free_dmmap_config_dup_list(&dup_list);
return 0;
}
/* *** Device.XMPP. *** */
DMOBJ tDeviceXMPPObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"XMPP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tXMPPObj, tXMPPParams, NULL, BBFDM_BOTH},
{0}
};
DMOBJ tXMPPObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"Connection", &DMWRITE, add_xmpp_connection, delete_xmpp_connection, NULL, browsexmpp_connectionInst, NULL, NULL, NULL, tXMPPConnectionObj, tXMPPConnectionParams, NULL, BBFDM_BOTH},
{0}
};
DMLEAF tXMPPParams[] = {
/* PARAM, permission, type, getvalue, setvalue, forced_inform, notification, bbfdm_type*/
{"ConnectionNumberOfEntries", &DMREAD, DMT_UNINT, get_xmpp_connection_nbr_entry, NULL, NULL, NULL, BBFDM_BOTH},
{"SupportedServerConnectAlgorithms", &DMREAD, DMT_STRING, get_xmpp_connection_supported_server_connect_algorithms, NULL, NULL, NULL, BBFDM_BOTH},
{0}
};
/* *** Device.XMPP.Connection.{i}. *** */
DMOBJ tXMPPConnectionObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, forced_inform, notification, nextdynamicobj, nextobj, leaf, linker, bbfdm_type*/
{"Server", &DMREAD, NULL, NULL, NULL, browsexmpp_connection_serverInst, NULL, NULL, NULL, NULL, tXMPPConnectionServerParams, NULL, BBFDM_BOTH},
{0}
};
DMLEAF tXMPPConnectionParams[] = {
/* PARAM, permission, type, getvalue, setvalue, forced_inform, notification, bbfdm_type*/
{"Enable", &DMWRITE, DMT_BOOL, get_connection_enable, set_connection_enable, NULL, NULL, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_xmpp_connection_alias, set_xmpp_connection_alias, NULL, NULL, BBFDM_BOTH},
{"Username", &DMWRITE, DMT_STRING, get_xmpp_connection_username, set_xmpp_connection_username, NULL, NULL, BBFDM_BOTH},
{"Password", &DMWRITE, DMT_STRING, get_xmpp_connection_password, set_xmpp_connection_password, NULL, NULL, BBFDM_BOTH},
{"Domain", &DMWRITE, DMT_STRING, get_xmpp_connection_domain, set_xmpp_connection_domain, NULL, NULL, BBFDM_BOTH},
{"Resource", &DMWRITE, DMT_STRING, get_xmpp_connection_resource, set_xmpp_connection_resource, NULL, NULL, BBFDM_BOTH},
{"ServerConnectAlgorithm", &DMWRITE, DMT_STRING, get_xmpp_connection_server_connect_algorithm, set_xmpp_connection_server_connect_algorithm, NULL, NULL, BBFDM_BOTH},
{"KeepAliveInterval", &DMWRITE, DMT_LONG, get_xmpp_connection_keepalive_interval, set_xmpp_connection_keepalive_interval, NULL, NULL, BBFDM_BOTH},
{"ServerConnectAttempts", &DMWRITE, DMT_UNINT, get_xmpp_connection_server_attempts, set_xmpp_connection_server_attempts, NULL, NULL, BBFDM_BOTH},
{"ServerRetryInitialInterval", &DMWRITE, DMT_UNINT, get_xmpp_connection_retry_initial_interval, set_xmpp_connection_retry_initial_interval, NULL, NULL, BBFDM_BOTH},
{"ServerRetryIntervalMultiplier", &DMWRITE, DMT_UNINT, get_xmpp_connection_retry_interval_multiplier, set_xmpp_connection_retry_interval_multiplier, NULL, NULL, BBFDM_BOTH},
{"ServerRetryMaxInterval", &DMWRITE, DMT_UNINT, get_xmpp_connection_retry_max_interval, set_xmpp_connection_retry_max_interval, NULL, NULL, BBFDM_BOTH},
{"UseTLS", &DMWRITE, DMT_BOOL, get_xmpp_connection_server_usetls, set_xmpp_connection_server_usetls, NULL, NULL, BBFDM_BOTH},
{"JabberID", &DMREAD, DMT_STRING, get_xmpp_connection_jabber_id, NULL, NULL, NULL, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_xmpp_connection_status, NULL, NULL, NULL, BBFDM_BOTH},
{"ServerNumberOfEntries", &DMREAD, DMT_UNINT, get_xmpp_connection_server_number_of_entries, NULL, NULL, NULL, BBFDM_BOTH},
{0}
};
/* *** Device.XMPP.Connection.{i}.Server.{i}. *** */
DMLEAF tXMPPConnectionServerParams[] = {
/* PARAM, permission, type, getvalue, setvalue, forced_inform, notification, bbfdm_type*/
{"Enable", &DMWRITE, DMT_BOOL, get_xmpp_connection_server_enable, set_xmpp_connection_server_enable, NULL, NULL, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_xmpp_connection_server_alias, set_xmpp_connection_server_alias, NULL, NULL, BBFDM_BOTH},
{"ServerAddress", &DMWRITE, DMT_STRING, get_xmpp_connection_server_server_address, set_xmpp_connection_server_server_address, NULL, NULL, BBFDM_BOTH},
{"Port", &DMWRITE, DMT_UNINT, get_xmpp_connection_server_port, set_xmpp_connection_server_port, NULL, NULL, BBFDM_BOTH},
{0}
};

21
xmpp/src/datamodel.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2020 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
*/
#ifndef _XMPP_H_
#define _XMPP_H_
extern DMOBJ tDeviceXMPPObj[];
extern DMOBJ tXMPPObj[];
extern DMLEAF tXMPPParams[];
extern DMLEAF tXMPPConnectionParams[];
extern DMOBJ tXMPPConnectionObj[];
extern DMLEAF tXMPPConnectionServerParams[];
#endif //_XMPP_H_

Some files were not shown because too many files have changed in this diff Show More