From dde621e52c9e892898aae15e0e6fa8aff7a4530e Mon Sep 17 00:00:00 2001 From: "imen.bhiri" Date: Tue, 6 Dec 2016 15:59:52 +0100 Subject: [PATCH] Ticket refs #10493 : Upload and Download diagnostics --- bin/Makefile.am | 7 +- configure.ac | 3 + cwmp.c | 13 +- diagnostic.c | 720 ++++++++++++++++++ dm/dmcwmp.c | 4 + dm/dmtree/common/softwaremodules.c | 2 +- dm/dmtree/tr098/downloaddiagnostic.c | 225 ++++++ .../dmtree/tr098/downloaddiagnostic.h | 11 +- dm/dmtree/tr098/ippingdiagnostics.c | 3 +- dm/dmtree/tr098/uploaddiagnostic.c | 245 ++++++ dm/dmtree/tr098/uploaddiagnostic.h | 15 + dm/dmtree/tr181/ip.c | 2 +- inc/cwmp.h | 2 + inc/diagnostic.h | 79 ++ ipping.c | 28 - scripts/functions/download_launch | 57 ++ scripts/functions/upload_launch | 75 ++ 17 files changed, 1450 insertions(+), 41 deletions(-) create mode 100644 diagnostic.c create mode 100644 dm/dmtree/tr098/downloaddiagnostic.c rename inc/ipping.h => dm/dmtree/tr098/downloaddiagnostic.h (65%) create mode 100644 dm/dmtree/tr098/uploaddiagnostic.c create mode 100644 dm/dmtree/tr098/uploaddiagnostic.h create mode 100644 inc/diagnostic.h delete mode 100644 ipping.c create mode 100755 scripts/functions/download_launch create mode 100644 scripts/functions/upload_launch diff --git a/bin/Makefile.am b/bin/Makefile.am index b8a2d19..37415e5 100644 --- a/bin/Makefile.am +++ b/bin/Makefile.am @@ -5,7 +5,7 @@ icwmpd_SOURCES = \ ../backupSession.c \ ../config.c \ ../cwmp.c \ - ../ipping.c \ + ../diagnostic.c \ ../digestauth.c \ ../event.c \ ../external.c \ @@ -53,7 +53,9 @@ icwmpd_SOURCES += \ ../dm/dmtree/tr098/layer_2_bridging.c \ ../dm/dmtree/tr098/wandevice.c \ ../dm/dmtree/tr098/x_inteno_se_wifi.c \ - ../dm/dmtree/tr098/ippingdiagnostics.c \ + ../dm/dmtree/tr098/ippingdiagnostics.c \ + ../dm/dmtree/tr098/downloaddiagnostic.c \ + ../dm/dmtree/tr098/uploaddiagnostic.c \ ../dm/dmtree/tr098/layer_3_forwarding.c endif if DATAMODEL_TR181 @@ -94,6 +96,7 @@ icwmpd_LDADD = \ $(LIBUBUS_LIBS) \ $(MICROXML_LIBS) \ $(LIBCURL_LIBS) \ + $(LIBTRACE_LIBS) \ $(LIBZSTREAM_LIBS) \ $(LIBPTHREAD_LIBS) \ $(LCRYPTO_LIBS) \ diff --git a/configure.ac b/configure.ac index 9d18398..7b70f9d 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,9 @@ AC_SUBST([LIBUCI_LDFLAGS]) LIBUCI_LIBS='-luci' AC_SUBST([LIBUCI_LIBS]) +LIBTRACE_LIBS='-ltrace' +AC_SUBST([LIBTRACE_LIBS]) + AC_ARG_WITH([libubox-include-path], [AS_HELP_STRING([--with-libubox-include-path], [location of the libubox library headers])], diff --git a/cwmp.c b/cwmp.c index b6d2f3f..23774ac 100644 --- a/cwmp.c +++ b/cwmp.c @@ -23,7 +23,7 @@ #include "external.h" #include "dmentry.h" #include "ubus.h" -#include "ipping.h" +#include "diagnostic.h" #include "xmpp_cr.h" #ifdef XMPP_ENABLE #include @@ -553,6 +553,17 @@ int run_session_end_func (struct session *session) cwmp_ip_ping_diagnostic(); } + if (session->end_session & END_SESSION_DOWNLOAD_DIAGNOSTIC) + { + CWMP_LOG (INFO,"Executing download diagnostic: end session request"); + cwmp_start_diagnostic(DOWNLOAD_DIAGNOSTIC); + } + + if (session->end_session & END_SESSION_UPLOAD_DIAGNOSTIC) + { + CWMP_LOG (INFO,"Executing upload diagnostic: end session request"); + cwmp_start_diagnostic(UPLOAD_DIAGNOSTIC); + } if (session->end_session & END_SESSION_REBOOT) { CWMP_LOG (INFO,"Executing Reboot: end session request"); diff --git a/diagnostic.c b/diagnostic.c new file mode 100644 index 0000000..addadf1 --- /dev/null +++ b/diagnostic.c @@ -0,0 +1,720 @@ +/* + * 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) 2013 Inteno Broadband Technology AB + * Author Imen Bhiri * + * + */ + +#include +#include +#include +#include "cwmp.h" +#include "backupSession.h" +#include "xml.h" +#include "log.h" +#include "external.h" +#include "dmentry.h" +#include "ubus.h" +#include "diagnostic.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int read_next; +struct download_diag download_stats = {0}; +struct upload_diagnostic_stats upload_stats = {0}; + +static void http_upload_per_packet(libtrace_packet_t *packet); +static void libtrace_cleanup(libtrace_t *trace, libtrace_packet_t *packet); +static void set_download_stats(); +static void set_upload_stats(); +int init_download_stats() +{ + memset(&download_stats, 0, sizeof(download_stats)); +} + +int init_upload_stats() +{ + memset(&upload_stats, 0, sizeof(upload_stats)); +} + +static void ftp_download_per_packet(libtrace_packet_t *packet, int first_packet) +{ + struct tm lt; + struct timeval ts; + libtrace_tcp_t *tcp; + char tcp_flag[16] = ""; + char *nexthdr; + libtrace_ip_t *ip; + char s_now[default_date_size]; + uint8_t proto; + uint32_t remaining; + tcp = trace_get_transport(packet, &proto, &remaining); + + if (tcp == NULL) + { + return; + } + else + { + nexthdr = trace_get_payload_from_tcp(tcp, &remaining); + } + if (tcp->ecn_ns) strcat(tcp_flag, "ECN_NS "); + if (tcp->cwr) strcat(tcp_flag, "CWR "); + if (tcp->ece) strcat(tcp_flag, "ECE "); + if (tcp->fin) strcat(tcp_flag, "FIN "); + if (tcp->syn) strcat(tcp_flag, "SYN "); + if (tcp->rst) strcat(tcp_flag, "RST "); + if (tcp->psh) strcat(tcp_flag, "PSH "); + if (tcp->ack) strcat(tcp_flag, "ACK "); + if (tcp->urg) strcat(tcp_flag, "URG "); + if (strcmp(tcp_flag, "PSH ACK ") == 0 && strlen(nexthdr) > strlen(FTP_SIZE_RESPONSE) && strncmp(nexthdr, FTP_SIZE_RESPONSE, strlen(FTP_SIZE_RESPONSE)) == 0) + { + char *val = strstr(nexthdr,"213"); + char *pch, *pchr; + val += strlen("213 "); + pch=strtok_r(val, " \r\n\t", &pchr); + download_stats.test_bytes_received = atoi(pch); + } + if(strcmp(tcp_flag, "PSH ACK ") == 0 && strlen(nexthdr) > strlen(FTP_PASV_RESPONSE) && strncmp(nexthdr, FTP_PASV_RESPONSE, strlen(FTP_PASV_RESPONSE)) == 0) + { + download_stats.ftp_syn = 1; + return; + } + if (download_stats.random_seq == 0 && strcmp(tcp_flag, "SYN ") == 0 && download_stats.ftp_syn == 1) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + download_stats.random_seq = ntohl(tcp->seq); + sprintf((download_stats.tcpopenrequesttime),"%s.%06ld", s_now, (long) ts.tv_usec); + } + if (strcmp(tcp_flag, "SYN ACK ") == 0 && download_stats.random_seq != 0 && (ntohl(tcp->ack_seq) - 1 ) == download_stats.random_seq) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((download_stats.tcpopenresponsetime),"%s.%06ld", s_now, (long) ts.tv_usec); + download_stats.random_seq = ntohl(tcp->ack_seq); + sprintf((download_stats.tcpopenresponsetime),"%s.%06ld", s_now, (long) ts.tv_usec); + } + + if (strcmp(tcp_flag, "PSH ACK ") == 0 && strlen(nexthdr) > strlen(FTP_RETR_REQUEST) && strncmp(nexthdr, FTP_RETR_REQUEST, strlen(FTP_RETR_REQUEST)) == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((download_stats.romtime),"%s.%06ld", s_now, (long) ts.tv_usec); + } + if(strcmp(tcp_flag, "ACK ") == 0 && ntohl(tcp->seq) == download_stats.random_seq && download_stats.ack_seq == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + download_stats.ack_seq = ntohl(tcp->seq); + return; + } + if(strcmp(tcp_flag, "ACK ") == 0 && ntohl(tcp->ack_seq) == download_stats.ack_seq ) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (download_stats.first_data == 0) + { + sprintf((download_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + } + download_stats.first_data = 1; + ip = trace_get_ip(packet); + if (ip != NULL) + download_stats.total_bytes_received += ntohs(ip->ip_len); + } + if ( (strcmp(tcp_flag, "PSH ACK ") == 0 || strcmp(tcp_flag, "FIN PSH ACK ") == 0) && ntohl(tcp->ack_seq) == download_stats.ack_seq) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (download_stats.first_data == 0) + { + sprintf((download_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + download_stats.first_data = 1; + } + sprintf((download_stats.eomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + ip = trace_get_ip(packet); + if (ip != NULL) + download_stats.total_bytes_received += ntohs(ip->ip_len); + } +} + + +static void http_download_per_packet(libtrace_packet_t *packet, int first_packet) +{ + struct tm lt; + struct timeval ts; + libtrace_tcp_t *tcp; + uint32_t seq = 0; + char tcp_flag[16] = ""; + char *nexthdr; + libtrace_ip_t *ip; + char s_now[default_date_size]; + + uint8_t proto; + uint32_t remaining; + tcp = trace_get_transport(packet, &proto, &remaining); + + if (tcp == NULL) + { + return; + } + else + { + nexthdr = trace_get_payload_from_tcp(tcp, &remaining); + } + if (tcp->ecn_ns) strcat(tcp_flag, "ECN_NS "); + if (tcp->cwr) strcat(tcp_flag, "CWR "); + if (tcp->ece) strcat(tcp_flag, "ECE "); + if (tcp->fin) strcat(tcp_flag, "FIN "); + if (tcp->syn) strcat(tcp_flag, "SYN "); + if (tcp->rst) strcat(tcp_flag, "RST "); + if (tcp->psh) strcat(tcp_flag, "PSH "); + if (tcp->ack) strcat(tcp_flag, "ACK "); + if (tcp->urg) strcat(tcp_flag, "URG "); + if (strcmp(tcp_flag, "SYN ") == 0 && download_stats.random_seq == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((download_stats.tcpopenrequesttime),"%s.%06ld", s_now, (long) ts.tv_usec); + download_stats.random_seq = ntohl(tcp->seq); + return; + } + if (strcmp(tcp_flag, "SYN ACK ") == 0 && download_stats.random_seq != 0 && (ntohl(tcp->ack_seq) - 1 ) == download_stats.random_seq) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((download_stats.tcpopenresponsetime),"%s.%06ld", s_now, (long) ts.tv_usec); + download_stats.random_seq = ntohl(tcp->seq); + return; + } + + if (strcmp(tcp_flag, "PSH ACK ") == 0 && strncmp(nexthdr, "GET", 3) == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((download_stats.romtime),"%s.%06ld", s_now, (long) ts.tv_usec); + download_stats.get_ack = ntohl(tcp->ack_seq); + return; + } + if(strcmp(tcp_flag, "ACK ") == 0 && ntohl(tcp->seq) == download_stats.get_ack && download_stats.ack_seq == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + download_stats.ack_seq = ntohl(tcp->ack_seq); + return; + } + if(strcmp(tcp_flag, "ACK ") == 0 && ntohl(tcp->ack_seq) == download_stats.ack_seq ) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (download_stats.first_data == 0) + { + sprintf((download_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + char *val = strstr(nexthdr,"Content-Length"); + char *pch, *pchr; + val += strlen("Content-Length: "); + pch=strtok_r(val, " \r\n\t", &pchr); + download_stats.test_bytes_received = atoi(pch); + download_stats.first_data = 1; + } + ip = trace_get_ip(packet); + if (ip != NULL) + { + download_stats.total_bytes_received += ntohs(ip->ip_len); + } + return; + } + if ( (strcmp(tcp_flag, "PSH ACK ") == 0 || strcmp(tcp_flag, "FIN PSH ACK ") == 0) && ntohl(tcp->ack_seq) == download_stats.ack_seq) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (download_stats.first_data == 0) + { + sprintf((download_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + char *val = strstr(nexthdr,"Content-Length"); + char *pch, *pchr; + val += strlen("Content-Length: "); + pch=strtok_r(val, " \r\n\t", &pchr); + download_stats.test_bytes_received = atoi(pch); + download_stats.first_data = 1; + } + + sprintf((download_stats.eomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + ip = trace_get_ip(packet); + if (ip != NULL) + { + download_stats.total_bytes_received += ntohs(ip->ip_len); + } + return; + } +} + +static void libtrace_cleanup(libtrace_t *trace, libtrace_packet_t *packet) +{ + if (trace) + trace_destroy(trace); + + if (packet) + trace_destroy_packet(packet); +} + +static void set_download_stats() +{ + char buf[128]; + sprintf(buf,"cwmp.@downloaddiagnostic[0].ROMtime=%s", download_stats.romtime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@downloaddiagnostic[0].BOMtime=%s", download_stats.bomtime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@downloaddiagnostic[0].EOMtime=%s", download_stats.eomtime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@downloaddiagnostic[0].TCPOpenRequestTime=%s", download_stats.tcpopenrequesttime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@downloaddiagnostic[0].TCPOpenResponseTime=%s", download_stats.tcpopenresponsetime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@downloaddiagnostic[0].TestBytesReceived=%d", download_stats.test_bytes_received); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@downloaddiagnostic[0].TotalBytesReceived=%lu", download_stats.total_bytes_received); + uci_set_state_value(buf); +} + +static void set_upload_stats() +{ + + char buf[128]; + sprintf(buf,"cwmp.@uploaddiagnostic[0].ROMtime=%s", upload_stats.romtime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@uploaddiagnostic[0].BOMtime=%s", upload_stats.bomtime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@uploaddiagnostic[0].EOMtime=%s", upload_stats.eomtime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@uploaddiagnostic[0].TCPOpenRequestTime=%s", upload_stats.tcpopenrequesttime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@uploaddiagnostic[0].TCPOpenResponseTime=%s", upload_stats.tcpopenresponsetime); + uci_set_state_value(buf); + sprintf(buf,"cwmp.@uploaddiagnostic[0].TotalBytesSent=%lu", upload_stats.total_bytes_sent); + uci_set_state_value(buf); +} + +static void http_upload_per_packet(libtrace_packet_t *packet) +{ + struct tm lt; + struct timeval ts; + libtrace_tcp_t *tcp; + //uint32_t remaining; + char tcp_flag[16] = ""; + char *nexthdr; + + libtrace_ip_t *ip; + char s_now[default_date_size]; + uint8_t proto; + uint32_t remaining; + tcp = trace_get_transport(packet, &proto, &remaining); + if (tcp == NULL) + { + return; + } + else + { + nexthdr = trace_get_payload_from_tcp(tcp, &remaining); + } + if (tcp->ecn_ns) strcat(tcp_flag, "ECN_NS "); + if (tcp->cwr) strcat(tcp_flag, "CWR "); + if (tcp->ece) strcat(tcp_flag, "ECE "); + if (tcp->fin) strcat(tcp_flag, "FIN "); + if (tcp->syn) strcat(tcp_flag, "SYN "); + if (tcp->rst) strcat(tcp_flag, "RST "); + if (tcp->psh) strcat(tcp_flag, "PSH "); + if (tcp->ack) strcat(tcp_flag, "ACK "); + if (tcp->urg) strcat(tcp_flag, "URG "); + if (strcmp(tcp_flag, "SYN ") == 0 && download_stats.random_seq == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((upload_stats.tcpopenrequesttime),"%s.%06ld", s_now, (long) ts.tv_usec); + upload_stats.random_seq = ntohl(tcp->seq); + } + if (strcmp(tcp_flag, "SYN ACK ") == 0 && upload_stats.random_seq != 0 && (ntohl(tcp->ack_seq) - 1 ) == upload_stats.random_seq) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((upload_stats.tcpopenresponsetime),"%s.%06ld", s_now, (long) ts.tv_usec); + upload_stats.random_seq = ntohl(tcp->seq); + } + if (strcmp(tcp_flag, "PSH ACK ") == 0 && strncmp(nexthdr, "PUT", 3) == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((upload_stats.romtime),"%s.%06ld", s_now, (long) ts.tv_usec); + if (strstr(nexthdr, "Expect: 100-continue")) + { + upload_stats.tmp=1; + upload_stats.ack_seq = ntohl(tcp->ack_seq); + } + else + upload_stats.ack_seq = ntohl(tcp->ack_seq); + return; + } + if (strcmp(tcp_flag, "PSH ACK ") == 0 && upload_stats.tmp == 1 && strstr(nexthdr, "100 Continue")) + { + upload_stats.tmp = 2; + upload_stats.ack_seq = ntohl(tcp->ack_seq); + return; + } + + if (strcmp(tcp_flag, "ACK ") == 0 && upload_stats.tmp == 2 && ntohl(tcp->seq) == upload_stats.ack_seq) + { + upload_stats.tmp = 0; + upload_stats.ack_seq = ntohl(tcp->ack_seq); + return; + } + + if(strcmp(tcp_flag, "ACK ") == 0 && ntohl(tcp->ack_seq) == upload_stats.ack_seq && upload_stats.tmp == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (upload_stats.first_data == 0) + { + sprintf((upload_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + upload_stats.first_data = 1; + } + ip = trace_get_ip(packet); + if (ip != NULL) + upload_stats.total_bytes_sent += ntohs(ip->ip_len); + } + if ( (strcmp(tcp_flag, "PSH ACK ") == 0 || strcmp(tcp_flag, "FIN PSH ACK ") == 0) && ntohl(tcp->ack_seq) == upload_stats.ack_seq && upload_stats.tmp == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (upload_stats.first_data == 0) + { + + sprintf((upload_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + upload_stats.first_data = 1; + } + ip = trace_get_ip(packet); + if (ip != NULL) + upload_stats.total_bytes_sent += ntohs(ip->ip_len); + } + if ( (strcmp(tcp_flag, "PSH ACK ") == 0 || strcmp(tcp_flag, "FIN PSH ACK ") == 0) && ntohl(tcp->seq) == upload_stats.ack_seq && upload_stats.tmp == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((upload_stats.eomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + ip = trace_get_ip(packet); + } +} + +static void ftp_upload_per_packet(libtrace_packet_t *packet) +{ +struct tm lt; + struct timeval ts; + libtrace_tcp_t *tcp; + uint8_t proto; + uint32_t remaining; + char tcp_flag[16] = ""; + char *nexthdr; + libtrace_ip_t *ip; + char s_now[default_date_size]; + tcp = trace_get_transport(packet, &proto, &remaining); + if (tcp == NULL) + { + return; + } + else + { + nexthdr = trace_get_payload_from_tcp(tcp, &remaining); + } + + if (tcp->ecn_ns) strcat(tcp_flag, "ECN_NS "); + if (tcp->cwr) strcat(tcp_flag, "CWR "); + if (tcp->ece) strcat(tcp_flag, "ECE "); + if (tcp->fin) strcat(tcp_flag, "FIN "); + if (tcp->syn) strcat(tcp_flag, "SYN "); + if (tcp->rst) strcat(tcp_flag, "RST "); + if (tcp->psh) strcat(tcp_flag, "PSH "); + if (tcp->ack) strcat(tcp_flag, "ACK "); + if (tcp->urg) strcat(tcp_flag, "URG "); + if(strcmp(tcp_flag, "PSH ACK ") == 0 && strlen(nexthdr) > strlen(FTP_PASV_RESPONSE) + && strncmp(nexthdr, FTP_PASV_RESPONSE, strlen(FTP_PASV_RESPONSE)) == 0) + { + upload_stats.ftp_syn = 1; + return; + } + if (strcmp(tcp_flag, "SYN ") == 0 && upload_stats.ftp_syn == 1) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + upload_stats.random_seq = ntohl(tcp->seq); + sprintf((upload_stats.tcpopenrequesttime),"%s.%06ld", s_now, (long) ts.tv_usec); + } + if (strcmp(tcp_flag, "SYN ACK ") == 0 && upload_stats.random_seq != 0 && (ntohl(tcp->ack_seq) - 1 ) == upload_stats.random_seq) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((upload_stats.tcpopenresponsetime),"%s.%06ld", s_now, (long) ts.tv_usec); + upload_stats.random_seq = ntohl(tcp->ack_seq); + } + + if (strcmp(tcp_flag, "PSH ACK ") == 0 && strlen(nexthdr) > strlen(FTP_STOR_REQUEST) && strncmp(nexthdr, FTP_STOR_REQUEST, strlen(FTP_STOR_REQUEST)) == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((upload_stats.romtime),"%s.%06ld", s_now, (long) ts.tv_usec); + } + if(strcmp(tcp_flag, "ACK ") == 0 && ntohl(tcp->seq) == upload_stats.random_seq && upload_stats.ack_seq == 0) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + upload_stats.ack_seq = ntohl(tcp->ack_seq); + return; + } + if(strcmp(tcp_flag, "ACK ") == 0 && ntohl(tcp->ack_seq) == upload_stats.ack_seq ) + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (upload_stats.first_data == 0) + { + sprintf((upload_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + upload_stats.first_data = 1; + } + + ip = trace_get_ip(packet); + if (ip != NULL) + upload_stats.total_bytes_sent += ntohs(ip->ip_len); + } + if ( (strcmp(tcp_flag, "PSH ACK ") == 0 || strcmp(tcp_flag, "FIN PSH ACK ") == 0) && ntohl(tcp->ack_seq) == upload_stats.ack_seq) //&& strlen(nexthdr) > 16 && strncmp(nexthdr, "HTTP/1.1 200 OK", 16) == 0 + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + if (upload_stats.first_data == 0) + { + sprintf((upload_stats.bomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + upload_stats.first_data = 1; + } + ip = trace_get_ip(packet); + if (ip != NULL) + upload_stats.total_bytes_sent += ntohs(ip->ip_len); + } + if ( (strcmp(tcp_flag, "PSH ACK ") == 0 || strcmp(tcp_flag, "FIN PSH ACK ") == 0) && strlen(nexthdr) > strlen(FTP_TRANSFERT_COMPLETE) && strncmp(nexthdr, FTP_TRANSFERT_COMPLETE, strlen(FTP_TRANSFERT_COMPLETE)) == 0) //&& strlen(nexthdr) > 16 && strncmp(nexthdr, "HTTP/1.1 200 OK", 16) == 0 + { + ts = trace_get_timeval(packet); + (void) localtime_r(&(ts.tv_sec), <); + strftime(s_now, sizeof s_now, "%Y-%m-%dT%H:%M:%S", <); + sprintf((upload_stats.eomtime),"%s.%06ld", s_now, (long) ts.tv_usec); + read_next = 0; + } +} + +int extract_stats(char *dump_file, int proto, int diagnostic_type) +{ + libtrace_t *trace = NULL; + libtrace_packet_t *packet = NULL; + read_next = 1; + int first_packet = 1; + packet = trace_create_packet(); + if (packet == NULL) { + perror("Creating libtrace packet"); + libtrace_cleanup(trace, packet); + return 1; + } + trace = trace_create(dump_file); + if (!trace) { + return -1; + } + if (trace_is_err(trace)) { + trace_perror(trace,"Opening trace file"); + libtrace_cleanup(trace, packet); + return 1; + } + if (trace_start(trace) == -1) { + trace_perror(trace,"Starting trace"); + libtrace_cleanup(trace, packet); + return 1; + } + if (proto == DOWNLOAD_DIAGNOSTIC_HTTP && diagnostic_type == DOWNLOAD_DIAGNOSTIC) + { + while (trace_read_packet(trace,packet)>0 && read_next == 1) { + http_download_per_packet(packet, first_packet); + first_packet = 0; + continue; + } + set_download_stats(); + } + else if (proto == DOWNLOAD_DIAGNOSTIC_FTP && diagnostic_type == DOWNLOAD_DIAGNOSTIC) + { + while (trace_read_packet(trace,packet)>0 && read_next == 1) { + ftp_download_per_packet(packet, first_packet); + first_packet = 0; + continue; + } + set_download_stats(); + } + else if (proto == DOWNLOAD_DIAGNOSTIC_HTTP && diagnostic_type == UPLOAD_DIAGNOSTIC) + { + while (trace_read_packet(trace,packet)>0 && read_next == 1) { + http_upload_per_packet(packet); + first_packet = 0; + continue; + } + set_upload_stats(); + } + else + { + while (trace_read_packet(trace,packet)>0 && read_next == 1) { + ftp_upload_per_packet(packet); + first_packet = 0; + continue; + } + set_upload_stats(); + } + libtrace_cleanup(trace, packet); + return 0; +} + +int get_default_gateway_device( char **gw ) +{ + FILE *f; + char line[100] , *p , *c, *saveptr; + + f = fopen("/proc/net/route" , "r"); + if (f != NULL) + { + while(fgets(line , 100 , f)) + { + p = strtok_r(line , " \t", &saveptr); + c = strtok_r(NULL , " \t", &saveptr); + if(p!=NULL && c!=NULL) + { + if(strcmp(c , "00000000") == 0) + { + asprintf(gw, "%s", p); + fclose(f); + return 0; + } + } + } + fclose(f); + } + return -1; +} + +int cwmp_ip_ping_diagnostic() +{ + dmcmd_no_wait("/bin/sh", 2, FUNCTION_PATH, "run"); + return 0; +} + +int cwmp_start_diagnostic(int diagnostic_type) +{ + char *url = NULL; + char *interface = NULL; + char *size = NULL; + int error; + char *status; + if (diagnostic_type == DOWNLOAD_DIAGNOSTIC) + uci_get_state_value("cwmp.@downloaddiagnostic[0].url", &url); + else + { + uci_get_state_value("cwmp.@uploaddiagnostic[0].url", &url); + uci_get_state_value("cwmp.@uploaddiagnostic[0].TestFileLength", &size); + } + + CWMP_LOG(DEBUG,"diagnostic url %s", url); + uci_get_state_value("cwmp.@downloaddiagnostic[0].interface", &interface); + if( url == NULL || ((url != NULL) && (strcmp(url,"")==0)) + || (strncmp(url,DOWNLOAD_PROTOCOL_FTP,strlen(DOWNLOAD_PROTOCOL_FTP))!=0) && + (strstr(url,"@") != NULL && strncmp(url,DOWNLOAD_PROTOCOL_HTTP,strlen(DOWNLOAD_PROTOCOL_HTTP)) == 0) + ) + { + CWMP_LOG(ERROR,"Invalid URL %s", url); + return -1; + } + if ( interface == NULL || interface[0] == '\0' ) + { + error = get_default_gateway_device(&interface); + if (error == -1) + { + CWMP_LOG(ERROR,"Interface value: Empty"); + return -1; + } + } + if (diagnostic_type == DOWNLOAD_DIAGNOSTIC) + { + dmcmd("/bin/sh", 4, DOWNLOAD_DIAGNOSTIC_PATH, "run", url, interface); + uci_get_state_value("cwmp.@downloaddiagnostic[0].DiagnosticState", &status); + if (status && strcmp(status, "Complete") == 0) + { + init_download_stats(); + CWMP_LOG(INFO,"Extract download stats"); + if(strncmp(url,DOWNLOAD_PROTOCOL_HTTP,strlen(DOWNLOAD_PROTOCOL_HTTP)) == 0) + extract_stats(DOWNLOAD_DUMP_FILE, DOWNLOAD_DIAGNOSTIC_HTTP, DOWNLOAD_DIAGNOSTIC); + if(strncmp(url,DOWNLOAD_PROTOCOL_FTP,strlen(DOWNLOAD_PROTOCOL_FTP)) == 0) + extract_stats(DOWNLOAD_DUMP_FILE, DOWNLOAD_DIAGNOSTIC_FTP, DOWNLOAD_DIAGNOSTIC); + cwmp_root_cause_event_ipdiagnostic(&cwmp_main); + } + else if (status && strncmp(status, "Error_", strlen("Error_")) == 0) + cwmp_root_cause_event_ipdiagnostic(&cwmp_main); + free(status); + } + else + { + dmcmd("/bin/sh", 5, UPLOAD_DIAGNOSTIC_PATH, "run", url, interface, size); + uci_get_state_value("cwmp.@uploaddiagnostic[0].DiagnosticState", &status); + if (status && strcmp(status, "Complete") == 0) + { + init_upload_stats(); + CWMP_LOG(INFO,"Extract upload stats"); + if(strncmp(url,DOWNLOAD_PROTOCOL_HTTP,strlen(DOWNLOAD_PROTOCOL_HTTP)) == 0) + extract_stats(UPLOAD_DUMP_FILE, DOWNLOAD_DIAGNOSTIC_HTTP, UPLOAD_DIAGNOSTIC); + if(strncmp(url,DOWNLOAD_PROTOCOL_FTP,strlen(DOWNLOAD_PROTOCOL_FTP)) == 0) + extract_stats(UPLOAD_DUMP_FILE, DOWNLOAD_DIAGNOSTIC_FTP, UPLOAD_DIAGNOSTIC); + cwmp_root_cause_event_ipdiagnostic(&cwmp_main); + } + else if (status && strncmp(status, "Error_", strlen("Error_")) == 0) + cwmp_root_cause_event_ipdiagnostic(&cwmp_main); + free(status); + free(size); + } + free(url); + free(interface); + return 0; +} + diff --git a/dm/dmcwmp.c b/dm/dmcwmp.c index 69adc09..e23b00e 100644 --- a/dm/dmcwmp.c +++ b/dm/dmcwmp.c @@ -46,6 +46,8 @@ #include "nat.h" #include "xmpp.h" #include "x_inteno_se_owsd.h" +#include "downloaddiagnostic.h" +#include "uploaddiagnostic.h" static char *get_parameter_notification (struct dmctx *ctx, char *param); static int remove_parameter_notification(char *param); @@ -114,6 +116,8 @@ struct prefix_method prefix_methods[] = { { DMROOT"X_INTENO_SE_Wifi.", 1, NULL, 0, &entry_method_root_SE_Wifi }, { DMROOT"Layer3Forwarding.", 1, NULL, 0, &entry_method_root_layer3_forwarding }, { DMROOT"IPPingDiagnostics.", 1, NULL, 0, &entry_method_root_IPPingDiagnostics }, + { DMROOT"DownloadDiagnostics.", 1, NULL, 0, &entry_method_root_Download_Diagnostics }, + { DMROOT"UploadDiagnostics.", 1, NULL, 0, &entry_method_root_Upload_Diagnostics }, #endif { DMROOT"Services.", 1, dm_service_enable_set, 0, &entry_method_root_Service }, { DMROOT"UPnP.", 1, NULL, 0, &entry_method_root_upnp }, diff --git a/dm/dmtree/common/softwaremodules.c b/dm/dmtree/common/softwaremodules.c index 3397650..ba9c14f 100644 --- a/dm/dmtree/common/softwaremodules.c +++ b/dm/dmtree/common/softwaremodules.c @@ -13,7 +13,7 @@ #include #include #include "cwmp.h" -#include "ipping.h" +#include "diagnostic.h" #include "ubus.h" #include "dmcwmp.h" #include "dmuci.h" diff --git a/dm/dmtree/tr098/downloaddiagnostic.c b/dm/dmtree/tr098/downloaddiagnostic.c new file mode 100644 index 0000000..44c4b13 --- /dev/null +++ b/dm/dmtree/tr098/downloaddiagnostic.c @@ -0,0 +1,225 @@ +/* + * 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) 2012-2014 PIVA SOFTWARE (www.pivasoftware.com) + * Author: Imen Bhiri + * Author: Feten Besbes + */ + +#include +#include +#include +#include "cwmp.h" +#include "diagnostic.h" +#include "ubus.h" +#include "dmcwmp.h" +#include "dmuci.h" +#include "dmubus.h" +#include "dmcommon.h" +#include "downloaddiagnostic.h" + +static inline char *download_diagnostic_get(char *option, char *def) +{ + char *tmp; + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", option, &tmp); + if(tmp && tmp[0] == '\0') + return dmstrdup(def); + else + return tmp; +} +int get_download_diagnostics_state(char *refparam, struct dmctx *ctx, char **value) +{ + *value = download_diagnostic_get("DiagnosticState", "None"); + return 0; +} + +int set_download_diagnostics_state(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + if (strcmp(value, "Requested") == 0) { + DOWNLOAD_DIAGNOSTIC_STOP + if(!curr_section) + { + dmuci_add_state_section("cwmp", "downloaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@downloaddiagnostic[0]", "DiagnosticState", value); + cwmp_set_end_session(END_SESSION_DOWNLOAD_DIAGNOSTIC); + } + return 0; + } + return 0; +} + +int get_download_diagnostics_interface(char *refparam, struct dmctx *ctx, char **value) +{ + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "interface", value); + return 0; +} + +int set_download_diagnostics_interface(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + DOWNLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "downloaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "downloaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@downloaddiagnostic[0]", "interface", value); + return 0; + } + return 0; +} + +int get_download_diagnostics_url(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "url", value); + return 0; +} + +int set_download_diagnostics_url(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + DOWNLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "downloaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "downloaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@downloaddiagnostic[0]", "url", value); + return 0; + } + return 0; +} + +int get_download_diagnostics_ethernet_priority(char *refparam, struct dmctx *ctx, char **value) +{ + *value = ""; + return 0; +} + +int set_download_diagnostics_ethernet_priority(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + DOWNLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "downloaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "downloaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@downloaddiagnostic[0]", "ethernetpriority", value); + return 0; + } + return 0; +} + +int get_download_diagnostic_romtime(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "ROMtime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_download_diagnostic_bomtime(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "BOMtime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_download_diagnostic_eomtime(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "EOMtime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_download_diagnostic_testbytes(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "TestBytesReceived", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_download_diagnostic_totalbytes(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "TotalBytesReceived", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_download_diagnostic_tcp_open_request_time(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "TCPOpenRequestTime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_download_diagnostic_tcp_open_response_time(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@downloaddiagnostic[0]", "TCPOpenResponseTime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + + + +int entry_method_root_Download_Diagnostics(struct dmctx *ctx) +{ + IF_MATCH(ctx, DMROOT"DownloadDiagnostics.") { + DMOBJECT(DMROOT"DownloadDiagnostics.", ctx, "0", 0, NULL, NULL, NULL); + DMPARAM("DiagnosticsState", ctx, "1", get_download_diagnostics_state, set_download_diagnostics_state, NULL, 0, 1, UNDEF, NULL); + //DMPARAM("Interface", ctx, "1", get_download_diagnostics_interface, set_download_diagnostics_interface, NULL, 0, 1, UNDEF, NULL); //TODO + DMPARAM("DownloadURL", ctx, "1", get_download_diagnostics_url, set_download_diagnostics_url, NULL, 0, 1, UNDEF, NULL); + //DMPARAM("DSCP", ctx, "1", get_download_diagnostics_dscp, set_download_diagnostics_dscp, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + DMPARAM("EthernetPriority", ctx, "1", get_download_diagnostics_ethernet_priority, set_download_diagnostics_ethernet_priority, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + DMPARAM("ROMTime", ctx, "0", get_download_diagnostic_romtime, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("BOMTime", ctx, "0", get_download_diagnostic_bomtime, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("EOMTime", ctx, "0", get_download_diagnostic_eomtime, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("TestBytesReceived", ctx, "0", get_download_diagnostic_testbytes, NULL, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + DMPARAM("TotalBytesReceived", ctx, "0", get_download_diagnostic_totalbytes, NULL, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + DMPARAM("TCPOpenRequestTime", ctx, "0", get_download_diagnostic_tcp_open_request_time, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("TCPOpenResponseTime", ctx, "0", get_download_diagnostic_tcp_open_response_time, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + return 0; + } + return FAULT_9005; +} diff --git a/inc/ipping.h b/dm/dmtree/tr098/downloaddiagnostic.h similarity index 65% rename from inc/ipping.h rename to dm/dmtree/tr098/downloaddiagnostic.h index 800956a..fa932aa 100644 --- a/inc/ipping.h +++ b/dm/dmtree/tr098/downloaddiagnostic.h @@ -7,10 +7,9 @@ * Copyright (C) 2012-2014 PIVA SOFTWARE (www.pivasoftware.com) * Author: Imen Bhiri */ -#ifndef __IPPING__H -#define __IPPING__H +#ifndef __DOWNLOAD_DIAGNOSTIC_H +#define __DOWNLOAD_DIAGNOSTIC_H -#define FUNCTION_PATH "/usr/share/icwmp/functions/ipping_launch" -#define IPPING_STOP DMCMD("/bin/sh", 2, FUNCTION_PATH, "stop"); -int cwmp_ip_ping_diagnostic(); -#endif \ No newline at end of file +int entry_method_root_Download_Diagnostics(struct dmctx *ctx); + +#endif diff --git a/dm/dmtree/tr098/ippingdiagnostics.c b/dm/dmtree/tr098/ippingdiagnostics.c index bca013a..e561c1c 100644 --- a/dm/dmtree/tr098/ippingdiagnostics.c +++ b/dm/dmtree/tr098/ippingdiagnostics.c @@ -13,14 +13,13 @@ #include #include #include "cwmp.h" -#include "ipping.h" +#include "diagnostic.h" #include "ubus.h" #include "dmcwmp.h" #include "dmuci.h" #include "dmubus.h" #include "dmcommon.h" #include "ippingdiagnostics.h" -#include "ipping.h" static inline char *ipping_get(char *option, char *def) { diff --git a/dm/dmtree/tr098/uploaddiagnostic.c b/dm/dmtree/tr098/uploaddiagnostic.c new file mode 100644 index 0000000..c0f569d --- /dev/null +++ b/dm/dmtree/tr098/uploaddiagnostic.c @@ -0,0 +1,245 @@ +/* + * 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) 2012-2014 PIVA SOFTWARE (www.pivasoftware.com) + * Author: Imen Bhiri + * Author: Feten Besbes + */ + +#include +#include +#include +#include "cwmp.h" +#include "diagnostic.h" +#include "ubus.h" +#include "dmcwmp.h" +#include "dmuci.h" +#include "dmubus.h" +#include "dmcommon.h" +#include "uploaddiagnostic.h" + +static inline char *upload_diagnostic_get(char *option, char *def) +{ + char *tmp; + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", option, &tmp); + if(tmp && tmp[0] == '\0') + return dmstrdup(def); + else + return tmp; +} +int get_upload_diagnostics_state(char *refparam, struct dmctx *ctx, char **value) +{ + *value = upload_diagnostic_get("DiagnosticState", "None"); + return 0; +} + +int set_upload_diagnostics_state(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + if (strcmp(value, "Requested") == 0) { + UPLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "downloaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "uploaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@uploaddiagnostic[0]", "DiagnosticState", value); + cwmp_set_end_session(END_SESSION_UPLOAD_DIAGNOSTIC); + } + return 0; + } + return 0; +} + +int get_upload_diagnostics_interface(char *refparam, struct dmctx *ctx, char **value) +{ + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "interface", value); + return 0; +} + +int set_upload_diagnostics_interface(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + UPLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "uploaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "uploaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@uploaddiagnostic[0]", "interface", value); + return 0; + } + return 0; +} + +int get_upload_diagnostics_url(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "url", value); + return 0; +} + +int set_upload_diagnostics_url(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + UPLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "uploaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "uploaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@uploaddiagnostic[0]", "url", value); + return 0; + } + return 0; +} + +int get_upload_diagnostics_ethernet_priority(char *refparam, struct dmctx *ctx, char **value) +{ + *value = ""; + return 0; +} + +int set_upload_diagnostics_ethernet_priority(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + UPLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "uploaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "uploaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@uploaddiagnostic[0]", "ethernetpriority", value); + return 0; + } + return 0; +} + +int get_upload_diagnostic_romtime(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "ROMtime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_upload_diagnostic_bomtime(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "BOMtime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_upload_diagnostic_eomtime(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "EOMtime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_upload_diagnostic_test_file_length(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "TestFileLength", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int set_upload_diagnostic_test_file_length(char *refparam, struct dmctx *ctx, int action, char *value) +{ + char *tmp; + struct uci_section *curr_section = NULL; + + switch (action) { + case VALUECHECK: + return 0; + case VALUESET: + UPLOAD_DIAGNOSTIC_STOP + curr_section = dmuci_walk_state_section("cwmp", "uploaddiagnostic", NULL, NULL, CMP_SECTION, NULL, NULL, GET_FIRST_SECTION); + if(!curr_section) + { + dmuci_add_state_section("cwmp", "uploaddiagnostic", &curr_section, &tmp); + } + dmuci_set_varstate_value("cwmp", "@uploaddiagnostic[0]", "TestFileLength", value); + return 0; + } + return 0; +} + +int get_upload_diagnostic_totalbytes(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "TotalBytesSent", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_upload_diagnostic_tcp_open_request_time(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "TCPOpenRequestTime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int get_upload_diagnostic_tcp_open_response_time(char *refparam, struct dmctx *ctx, char **value) +{ + + dmuci_get_varstate_string("cwmp", "@uploaddiagnostic[0]", "TCPOpenResponseTime", value); + if ((*value)[0] == '\0') + *value = "0"; + return 0; +} + +int entry_method_root_Upload_Diagnostics(struct dmctx *ctx) +{ + IF_MATCH(ctx, DMROOT"UploadDiagnostics.") { + DMOBJECT(DMROOT"UploadDiagnostics.", ctx, "0", 0, NULL, NULL, NULL); + DMPARAM("DiagnosticsState", ctx, "1", get_upload_diagnostics_state, set_upload_diagnostics_state, NULL, 0, 1, UNDEF, NULL); + //DMPARAM("Interface", ctx, "1", get_upload_diagnostics_interface, set_upload_diagnostics_interface, NULL, 0, 1, UNDEF, NULL); //TODO + DMPARAM("UploadURL", ctx, "1", get_upload_diagnostics_url, set_upload_diagnostics_url, NULL, 0, 1, UNDEF, NULL); + DMPARAM("TestFileLength", ctx, "1", get_upload_diagnostic_test_file_length, set_upload_diagnostic_test_file_length, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + //DMPARAM("DSCP", ctx, "1", get_upload_diagnostics_dscp, set_upload_diagnostics_dscp, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + DMPARAM("EthernetPriority", ctx, "1", get_upload_diagnostics_ethernet_priority, set_upload_diagnostics_ethernet_priority, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + DMPARAM("ROMTime", ctx, "0", get_upload_diagnostic_romtime, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("BOMTime", ctx, "0", get_upload_diagnostic_bomtime, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("EOMTime", ctx, "0", get_upload_diagnostic_eomtime, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("TotalBytesSent", ctx, "0", get_upload_diagnostic_totalbytes, NULL, "xsd:unsignedInt", 0, 1, UNDEF, NULL); + DMPARAM("TCPOpenRequestTime", ctx, "0", get_upload_diagnostic_tcp_open_request_time, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + DMPARAM("TCPOpenResponseTime", ctx, "0", get_upload_diagnostic_tcp_open_response_time, NULL, "xsd:dateTime", 0, 1, UNDEF, NULL); + return 0; + } + return FAULT_9005; +} diff --git a/dm/dmtree/tr098/uploaddiagnostic.h b/dm/dmtree/tr098/uploaddiagnostic.h new file mode 100644 index 0000000..598f628 --- /dev/null +++ b/dm/dmtree/tr098/uploaddiagnostic.h @@ -0,0 +1,15 @@ +/* + * 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) 2012-2014 PIVA SOFTWARE (www.pivasoftware.com) + * Author: Imen Bhiri + */ +#ifndef __UPLOAD_DIAGNOSTIC_H +#define __UPLOAD_DIAGNOSTIC_H + +int entry_method_root_Upload_Diagnostics(struct dmctx *ctx); + +#endif diff --git a/dm/dmtree/tr181/ip.c b/dm/dmtree/tr181/ip.c index 0c8a56b..273d6a1 100644 --- a/dm/dmtree/tr181/ip.c +++ b/dm/dmtree/tr181/ip.c @@ -18,7 +18,7 @@ #include "dmcwmp.h" #include "dmcommon.h" #include "ip.h" -#include "ipping.h" +#include "diagnostic.h" struct ip_args cur_ip_args = {0}; struct ipv4_args cur_ipv4_args = {0}; diff --git a/inc/cwmp.h b/inc/cwmp.h index 57c6481..253bbb9 100644 --- a/inc/cwmp.h +++ b/inc/cwmp.h @@ -98,6 +98,8 @@ enum end_session { END_SESSION_RELOAD = 1<<2, END_SESSION_FACTORY_RESET = 1<<3, END_SESSION_IPPING_DIAGNOSTIC = 1<<4, + END_SESSION_DOWNLOAD_DIAGNOSTIC = 1<<5, + END_SESSION_UPLOAD_DIAGNOSTIC = 1<<6, }; enum cwmp_start { diff --git a/inc/diagnostic.h b/inc/diagnostic.h new file mode 100644 index 0000000..42feeaa --- /dev/null +++ b/inc/diagnostic.h @@ -0,0 +1,79 @@ +/* + * 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) 2012-2014 PIVA SOFTWARE (www.pivasoftware.com) + * Author: Imen Bhiri + */ +#ifndef __DIAGNOSTIC__H +#define __DIAGNOSTIC__H + +#define FUNCTION_PATH "/usr/share/icwmp/functions/ipping_launch" +#define DOWNLOAD_DIAGNOSTIC_PATH "/usr/share/icwmp/functions/download_launch" +#define DOWNLOAD_DUMP_FILE "/tmp/download_dump" +#define IPPING_STOP DMCMD("/bin/sh", 2, FUNCTION_PATH, "stop"); +#define DOWNLOAD_DIAGNOSTIC_STOP DMCMD("/bin/sh", 2, DOWNLOAD_DIAGNOSTIC_PATH, "stop"); +#define UPLOAD_DIAGNOSTIC_PATH "/usr/share/icwmp/functions/upload_launch" +#define UPLOAD_DUMP_FILE "/tmp/upload_dump" +#define UPLOAD_DIAGNOSTIC_STOP DMCMD("/bin/sh", 2, UPLOAD_DIAGNOSTIC_PATH, "stop"); +#define default_date_format "AAAA-MM-JJTHH:MM:SS.000000Z" +#define default_date_size sizeof(default_date_format) + 1 +#define FTP_SIZE_RESPONSE "213" +#define FTP_PASV_RESPONSE "227 Entering Passive" +#define FTP_TRANSFERT_COMPLETE "226 Transfer" +#define FTP_RETR_REQUEST "RETR" +#define FTP_STOR_REQUEST "STOR" + +struct download_diag +{ + char romtime[default_date_size]; + char bomtime[default_date_size]; + char eomtime[default_date_size]; + int test_bytes_received; + unsigned long total_bytes_received; + char tcpopenrequesttime[default_date_size]; + char tcpopenresponsetime[default_date_size]; + int tmp; + int first_data; + uint16_t ip_len; + uint32_t ack_seq; + uint32_t random_seq; + uint32_t get_ack; + uint32_t ftp_syn; +}; + +struct upload_diagnostic_stats +{ + char romtime[default_date_size]; + char bomtime[default_date_size]; + char eomtime[default_date_size]; + int test_bytes_received; + unsigned long total_bytes_sent; + char tcpopenrequesttime[default_date_size]; + char tcpopenresponsetime[default_date_size]; + int tmp; + int first_data; + uint16_t ip_len; + uint32_t ack_seq; + uint32_t random_seq; + uint32_t get_ack; + uint32_t ftp_syn; +}; + + +enum download_diagnostic_protocol { + DOWNLOAD_DIAGNOSTIC_HTTP = 1, + DOWNLOAD_DIAGNOSTIC_FTP +}; + +enum diagnostic_type { + DOWNLOAD_DIAGNOSTIC = 1, + UPLOAD_DIAGNOSTIC +}; + +int cwmp_ip_ping_diagnostic(); +int cwmp_start_diagnostic(int diagnostic_type); + +#endif diff --git a/ipping.c b/ipping.c deleted file mode 100644 index ad9b32b..0000000 --- a/ipping.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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) 2013 Inteno Broadband Technology AB - * Author Imen Bhiri * - * - */ - -#include -#include -#include -#include "cwmp.h" -#include "backupSession.h" -#include "xml.h" -#include "log.h" -#include "external.h" -#include "dmentry.h" -#include "ubus.h" -#include "ipping.h" - -int cwmp_ip_ping_diagnostic() -{ - dmcmd_no_wait("/bin/sh", 2, FUNCTION_PATH, "run"); - return 0; -} \ No newline at end of file diff --git a/scripts/functions/download_launch b/scripts/functions/download_launch new file mode 100755 index 0000000..4871eff --- /dev/null +++ b/scripts/functions/download_launch @@ -0,0 +1,57 @@ +#!/bin/sh +# Copyright (C) 2015 PIVA Software +# Author: IMEN Bhiri + + +UCI_CONFIG_DIR="/etc/config/" +UCI_GET_VARSTATE="/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state get -q " +UCI_SET_VARSTATE="/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state set -q " +CAPTURE_FILE="/tmp/download_dump" +DOWNLOAD_DIAGNOSTIC_FILE="/tmp/icwmp_download_diagnostic" + +download_launch() { + url=$1 + interface=$2 + tcpdump -i $interface tcp -w ${CAPTURE_FILE} > /dev/null 2>&1 & + PID=$! + sleep 1 + if [ ${url:0:7} = http:// -o ${url:0:6} = ftp:// ]; then + res=$(wget -O ${DOWNLOAD_DIAGNOSTIC_FILE} $url 2>&1) + ba=`echo "$res" | grep "bad address"` + [ -n "$ba" ] && { $UCI_SET_VARSTATE cwmp.@downloaddiagnostic[0].DiagnosticState=Error_InitConnectionFailed; kill $PID 2> /dev/null; return; } + stc=`echo "$res" | grep "404 Not Found"` + [ -n "$stc" ] && { $UCI_SET_VARSTATE cwmp.@downloaddiagnostic[0].DiagnosticState=Error_NoResponse; kill $PID 2> /dev/null; return; } + stc=`echo "$res" | grep "100%"` + [ -z "$stc" ] && { $UCI_SET_VARSTATE cwmp.@downloaddiagnostic[0].DiagnosticState=Error_TransferFaile; kill $PID 2> /dev/null; return; } + fi + $UCI_SET_VARSTATE cwmp.@downloaddiagnostic[0].DiagnosticState=Complete + rm ${DOWNLOAD_DIAGNOSTIC_FILE} 2>/dev/null + sleep 1 + local pids=`ps | grep $PID` + kill $PID &>/dev/null +} + +download_stop_diagnostic() { + local pids=`ps | grep download_launch.*run | grep -v grep | awk '{print $1}'` + if [ -n "$pids" ]; then + kill -9 $pids &>/dev/null + $UCI_SET_VARSTATE cwmp.@downloaddiagnostic[0].DiagnosticState=None + fi + local pids=`ps | grep upload_launch.*run | grep -v grep | awk '{print $1}'` + if [ -n "$pids" ]; then + kids=$(grep -l "PPid.*$pids" /proc/*/task/*/status | grep -o "[0-9]*") + for kid in $kids; do + kill -9 $kid &>/dev/null + done + kill -9 $pids &>/dev/null + $UCI_SET_VARSTATE cwmp.@downloaddiagnostic[0].DiagnosticState=None + fi +} + +if [ "$1" == "run" ] ; then + download_launch $2 $3 +elif [ "$1" == "stop" ]; then + download_stop_diagnostic +else + return +fi diff --git a/scripts/functions/upload_launch b/scripts/functions/upload_launch new file mode 100644 index 0000000..fb1d9b8 --- /dev/null +++ b/scripts/functions/upload_launch @@ -0,0 +1,75 @@ +#!/bin/sh +# Copyright (C) 2015 PIVA Software +# Author: IMEN Bhiri + + +UCI_CONFIG_DIR="/etc/config/" +UCI_GET_VARSTATE="/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state get -q " +UCI_SET_VARSTATE="/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state set -q " +CAPTURE_FILE="/tmp/upload_dump" +UPLOAD_DIAGNOSTIC_FILE="/tmp/icwmp_upload_diagnostic" +CONNECTION_TIMEOUT=20 + +upload_launch() { + url=$1 + interface=$2 + size=$3 + tcpdump -i $interface tcp -w ${CAPTURE_FILE} > /dev/null 2>&1 & + PID=$! + sleep 1 + dd if=/dev/zero of=${UPLOAD_DIAGNOSTIC_FILE} bs=${size} count=1 2>/dev/null + if [ ${url:0:7} = http:// ]; then + res=$(curl --fail --connect-timeout ${CONNECTION_TIMEOUT} -T ${UPLOAD_DIAGNOSTIC_FILE} $url 2>&1) + ba=`echo "$res" | grep "bad address"` + [ -n "$ba" ] && { $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Error_InitConnectionFailed; kill $PID &> /dev/null; return; } + stc=`echo "$res" | grep "404 Not Found"` + [ -n "$stc" ] && { $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Error_NoResponse; kill $PID &> /dev/null; return; } + stc=`echo "$res" |sed -n 3p|awk '{print $13}'` + [ "$stc" != "100" ] && { $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Error_TransferFailed; kill $PID &> /dev/null; return; } + elif [ ${url:0:6} = ftp:// ]; then + #add user and pass if they exist + substr="@" + if [ -z "${url##*$substr*}" ] ;then + url=`echo $url |sed -e "s/ftp:\/\/\([^:]*\):\([^:]*\)@\(.*\)/-u \1:\2 ftp:\/\/\3/"` + fi + res=$(curl --fail --connect-timeout ${CONNECTION_TIMEOUT} -T ${UPLOAD_DIAGNOSTIC_FILE} $url 2>&1) + ba=`echo "$res" | grep "Couldn't resolve host"` + [ -n "$ba" ] && { $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Error_InitConnectionFailed; kill $PID 2> /dev/null; return; } + stc=`echo "$res" | grep "Access denied"` + [ -n "$stc" ] && { $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Error_LoginFailed; kill $PID 2> /dev/null; return; } + stc=`echo "$res" | grep "Failed FTP upload"` + [ -n "$stc" ] && { $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Error_NoResponse; kill $PID 2> /dev/null; return; } + stc=`echo "$res" |tail -n 1 |awk '{print $(NF-11)}'` + [ "$stc" != "100" ] && { $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Error_TransferFailed; kill $PID 2> /dev/null; return; } + fi + $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=Complete + rm ${UPLOAD_DIAGNOSTIC_FILE} &>/dev/null + sleep 3 + local pids=`ps | grep $PID` + kill $PID &>/dev/null +} + +upload_stop_diagnostic() { + local pids=`ps | grep upload_launch.*run | grep -v grep | awk '{print $1}'` + if [ -n "$pids" ]; then + kill -9 $pids &>/dev/null + $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=None + fi + local pids=`ps | grep upload_launch.*run | grep -v grep | awk '{print $1}'` + if [ -n "$pids" ]; then + kids=$(grep -l "PPid.*$pids" /proc/*/task/*/status | grep -o "[0-9]*") + for kid in $kids; do + kill -9 $kid &>/dev/null + done + kill -9 $pids &>/dev/null + $UCI_SET_VARSTATE cwmp.@uploaddiagnostic[0].DiagnosticState=None + fi +} + +if [ "$1" == "run" ] ; then + upload_launch $2 $3 $4 +elif [ "$1" == "stop" ]; then + upload_stop_diagnostic +else + return +fi