Added Wireshark extcap command line parameter interface to mstpcap utility.
Tested with Wireshark on Windows (mostly working). To use extcap, run Wireshark and go to the About-dialog. Find a tab located there named "Folders". Locate the extcap search path. Copy the mstpcap.exe to that folder, which may not exist. Restart Wireshark, and look for "BACnet MS/TP on COMx" interfaces. Configure the interface to change baud rate. Capture directly from the interface.
This commit is contained in:
@@ -47,11 +47,15 @@
|
||||
#include "rs485.h"
|
||||
#include "crc.h"
|
||||
#include "mstptext.h"
|
||||
#include "filename.h"
|
||||
#include "version.h"
|
||||
#include "dlmstp.h"
|
||||
/* I-Am decoding */
|
||||
#include "iam.h"
|
||||
|
||||
/* define our Data Link Type for libPCAP */
|
||||
#define DLT_BACNET_MS_TP 165
|
||||
/* local min/max macros */
|
||||
#ifndef max
|
||||
#define max(a,b) (((a) (b)) ? (a) : (b))
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
@@ -309,12 +313,12 @@ static void packet_statistics_print(
|
||||
unsigned i; /* loop counter */
|
||||
unsigned node_count = 0;
|
||||
|
||||
fprintf(stdout, "\r\n");
|
||||
fprintf(stdout, "==== MS/TP Frame Counts ====\r\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "==== MS/TP Frame Counts ====\n");
|
||||
fprintf(stdout, "%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-7s", "MAC",
|
||||
"Device", "Tokens", "PFM", "RPFM", "DER", "Postpd", "DNER", "TestReq",
|
||||
"TestRsp");
|
||||
fprintf(stdout, "\r\n");
|
||||
fprintf(stdout, "\n");
|
||||
for (i = 0; i < MAX_MSTP_DEVICES; i++) {
|
||||
/* check for masters or slaves */
|
||||
if ((MSTP_Statistics[i].token_count) || (MSTP_Statistics[i].der_reply)
|
||||
@@ -337,17 +341,17 @@ static void packet_statistics_print(
|
||||
(long unsigned int) MSTP_Statistics[i].dner_count,
|
||||
(long unsigned int) MSTP_Statistics[i].test_request_count,
|
||||
(long unsigned int) MSTP_Statistics[i].test_response_count);
|
||||
fprintf(stdout, "\r\n");
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Node Count: %u\r\n", node_count);
|
||||
fprintf(stdout, "Node Count: %u\n", node_count);
|
||||
node_count = 0;
|
||||
fprintf(stdout, "\r\n");
|
||||
fprintf(stdout, "==== MS/TP Usage and Timing Maximums ====\r\n");
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, "==== MS/TP Usage and Timing Maximums ====\n");
|
||||
fprintf(stdout, "%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-8s%-7s", "MAC",
|
||||
"MaxMstr", "Retries", "Npoll", "Self", "Treply", "Tusage", "Trpfm",
|
||||
"Tder", "Tpostpd");
|
||||
fprintf(stdout, "\r\n");
|
||||
fprintf(stdout, "\n");
|
||||
for (i = 0; i < MAX_MSTP_DEVICES; i++) {
|
||||
/* check for masters or slaves */
|
||||
if ((MSTP_Statistics[i].token_count) || (MSTP_Statistics[i].der_reply)
|
||||
@@ -365,11 +369,11 @@ static void packet_statistics_print(
|
||||
(long unsigned int) MSTP_Statistics[i].pfm_reply,
|
||||
(long unsigned int) MSTP_Statistics[i].der_reply,
|
||||
(long unsigned int) MSTP_Statistics[i].reply_postponed);
|
||||
fprintf(stdout, "\r\n");
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Node Count: %u\r\n", node_count);
|
||||
fprintf(stdout, "Invalid Frame Count: %lu\r\n",
|
||||
fprintf(stdout, "Node Count: %u\n", node_count);
|
||||
fprintf(stdout, "Invalid Frame Count: %lu\n",
|
||||
(long unsigned int) Invalid_Frame_Count);
|
||||
}
|
||||
|
||||
@@ -430,16 +434,45 @@ static char Capture_Filename[32] = "mstp_20090123091200.cap";
|
||||
static FILE *pFile = NULL; /* stream pointer */
|
||||
#if defined(_WIN32)
|
||||
static HANDLE hPipe = NULL; /* pipe handle */
|
||||
|
||||
static PSECURITY_DESCRIPTOR pPipeSD = NULL;
|
||||
static void named_pipe_create(
|
||||
char *name)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
|
||||
pPipeSD = (PSECURITY_DESCRIPTOR)(malloc(SECURITY_DESCRIPTOR_MIN_LENGTH));
|
||||
if (!pPipeSD) {
|
||||
Exit_Requested = true;
|
||||
return;
|
||||
}
|
||||
if (!InitializeSecurityDescriptor(pPipeSD, SECURITY_DESCRIPTOR_REVISION)) {
|
||||
free(pPipeSD);
|
||||
pPipeSD = NULL;
|
||||
Exit_Requested = true;
|
||||
return;
|
||||
}
|
||||
/* When an object has no DACL (when the pDacl parameter is NULL),
|
||||
no protection is assigned to the object, and all access requests
|
||||
are granted. To help maintain security, restrict access by using
|
||||
a DACL. */
|
||||
if (!SetSecurityDescriptorDacl(pPipeSD, TRUE, (PACL)NULL, FALSE)) {
|
||||
free(pPipeSD);
|
||||
pPipeSD = NULL;
|
||||
Exit_Requested = true;
|
||||
return;
|
||||
}
|
||||
// now set up the security attributes
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
sa.lpSecurityDescriptor = pPipeSD;
|
||||
sa.bInheritHandle = TRUE;
|
||||
fprintf(stdout, "mstpcap: Creating Named Pipe \"%s\"\n", name);
|
||||
hPipe =
|
||||
CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
|
||||
PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, 65536, 65536, 300, NULL);
|
||||
PIPE_TYPE_MESSAGE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0L, &sa);
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
RS485_Print_Error();
|
||||
Exit_Requested = true;
|
||||
return;
|
||||
}
|
||||
ConnectNamedPipe(hPipe, NULL);
|
||||
@@ -551,7 +584,7 @@ static void write_global_header(
|
||||
int32_t thiszone = 0; /* GMT to local correction */
|
||||
uint32_t sigfigs = 0; /* accuracy of timestamps */
|
||||
uint32_t snaplen = 65535; /* max length of captured packets, in octets */
|
||||
uint32_t network = 165; /* data link type - BACNET_MS_TP */
|
||||
uint32_t network = DLT_BACNET_MS_TP; /* data link type - BACNET_MS_TP */
|
||||
|
||||
/* create a new file. */
|
||||
pFile = fopen(filename, "wb");
|
||||
@@ -686,7 +719,7 @@ static bool test_global_header(
|
||||
return false;
|
||||
}
|
||||
count = fread(&network, sizeof(network), 1, pFile);
|
||||
if ((count != 1) || (network != 165)) {
|
||||
if ((count != 1) || (network != DLT_BACNET_MS_TP)) {
|
||||
fprintf(stderr, "mstpcap: invalid data link type (DLT)\n");
|
||||
fclose(pFile);
|
||||
pFile = NULL;
|
||||
@@ -836,6 +869,9 @@ static BOOL WINAPI CtrlCHandler(
|
||||
DisconnectNamedPipe(hPipe);
|
||||
CloseHandle(hPipe);
|
||||
}
|
||||
if (pPipeSD) {
|
||||
free(pPipeSD);
|
||||
}
|
||||
/* signal to main loop to exit */
|
||||
Exit_Requested = true;
|
||||
while (Exit_Requested) {
|
||||
@@ -845,25 +881,6 @@ static BOOL WINAPI CtrlCHandler(
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Description: print available COM ports
|
||||
* Returns: none
|
||||
* Notes: none
|
||||
**************************************************************************/
|
||||
static void print_com_ports(
|
||||
void)
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
printf("List of available COM ports:\r\n");
|
||||
/* try to open all 255 COM ports */
|
||||
for (i = 1; i < 256; i++) {
|
||||
if (RS485_Interface_Valid(i)) {
|
||||
printf("COM%u\r\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void sig_int(
|
||||
int signo)
|
||||
@@ -896,6 +913,51 @@ void filename_create_new(
|
||||
write_global_header(&Capture_Filename[0]);
|
||||
}
|
||||
|
||||
static void print_usage(
|
||||
char *filename)
|
||||
{
|
||||
printf("Usage: %s", filename);
|
||||
printf(" [--scan <filename>]\n");
|
||||
printf(" [--extcap-interface port]\n");
|
||||
printf(" [--extcap-interfaces][--extcap-dlts][--extcap-config]\n");
|
||||
printf(" [--capture][--baud baud][--fifo pipe]\n");
|
||||
printf(" [--version][--help]\n");
|
||||
}
|
||||
|
||||
static void print_help(char *filename) {
|
||||
printf("%s --scan <filename>\n"
|
||||
"perform statistic analysis on MS/TP capture file.\n",
|
||||
filename);
|
||||
printf("\n");
|
||||
printf("Captures MS/TP packets from a serial interface\n"
|
||||
"and saves them to a file. Saves packets in a\n"
|
||||
"filename mstp_20090123091200.cap that has data and time.\n"
|
||||
"After receiving 65535 packets, a new file is created.\n" "\n"
|
||||
"Command line options:\n"
|
||||
"[--extcap-interface port] - serial interface.\n"
|
||||
#if defined(_WIN32)
|
||||
" Supported values: COM1, COM2, etc.\n"
|
||||
#else
|
||||
" Supported values: /dev/ttyS0, /dev/ttyUSB0, etc.\n"
|
||||
#endif
|
||||
"[--baud baud] - MS/TP port baud rate.\n"
|
||||
" Supported values: 9600, 19200, 38400, 57600, 76800, 115200.\n"
|
||||
" Defaults to 38400.\n"
|
||||
"[--fifo pipe] - FIFO pipe path and name\n"
|
||||
#if defined(_WIN32)
|
||||
" Supported values: \\\\.\\pipe\\wireshark\n"
|
||||
#else
|
||||
" Supported values: any file name\n"
|
||||
#endif
|
||||
" Use that name as the interface name in Wireshark.\n");
|
||||
printf("\n");
|
||||
printf("%s [--extcap-interfaces][--extcap-dlts][--extcap-config]\n"
|
||||
"[--capture][--baud baud][--fifo pipe]\n"
|
||||
"[--extcap-interface iface]\n"
|
||||
"Usage from Wireshark ExtCap interface\n",
|
||||
filename);
|
||||
}
|
||||
|
||||
/* simple test to packetize the data and print it */
|
||||
int main(
|
||||
int argc,
|
||||
@@ -904,6 +966,8 @@ int main(
|
||||
volatile struct mstp_port_struct_t *mstp_port;
|
||||
long my_baud = 38400;
|
||||
uint32_t packet_count = 0;
|
||||
int argi = 0;
|
||||
char *filename = NULL;
|
||||
|
||||
MSTP_Port.InputBuffer = &RxBuffer[0];
|
||||
MSTP_Port.InputBufferSize = sizeof(RxBuffer);
|
||||
@@ -918,40 +982,35 @@ int main(
|
||||
mstp_port = &MSTP_Port;
|
||||
MSTP_Init(mstp_port);
|
||||
packet_statistics_clear();
|
||||
/* initialize our interface */
|
||||
if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) {
|
||||
printf("mstpcap --scan <filename>\r\n"
|
||||
"perform statistic analysis on MS/TP capture file.\r\n");
|
||||
printf("\r\n");
|
||||
printf("mstpcap [interface] [baud] [named pipe]\r\n"
|
||||
"Captures MS/TP packets from a serial interface\r\n"
|
||||
"and save them to a file. Saves packets in a\r\n"
|
||||
"filename mstp_20090123091200.cap that has data and time.\r\n"
|
||||
"After receiving 65535 packets, a new file is created.\r\n" "\r\n"
|
||||
"Command line options:\r\n" "[interface] - serial interface.\r\n"
|
||||
" defaults to COM4 on Windows, and /dev/ttyUSB0 on linux.\r\n"
|
||||
"[baud] - baud rate. 9600, 19200, 38400, 57600, 115200\r\n"
|
||||
" defaults to 38400.\r\n"
|
||||
"[named pipe] - use \\\\.\\pipe\\wireshark as the name\r\n"
|
||||
" and set that name as the interface name in Wireshark\r\n");
|
||||
return 0;
|
||||
}
|
||||
if ((argc > 1) && (strcmp(argv[1], "--version") == 0)) {
|
||||
printf("mstpcap %s\r\n", BACNET_VERSION_TEXT);
|
||||
printf("Copyright (C) 2011 by Steve Karg\r\n"
|
||||
"This is free software; see the source for copying conditions.\r\n"
|
||||
"There is NO warranty; not even for MERCHANTABILITY or\r\n"
|
||||
"FITNESS FOR A PARTICULAR PURPOSE.\r\n");
|
||||
return 0;
|
||||
}
|
||||
if ((argc > 1) && (strcmp(argv[1], "--scan") == 0)) {
|
||||
if (argc > 2) {
|
||||
printf("Scanning %s\r\n", argv[2]);
|
||||
/* decode any command line parameters */
|
||||
filename = filename_remove_path(argv[0]);
|
||||
for (argi = 1; argi < argc; argi++) {
|
||||
if (strcmp(argv[argi], "--help") == 0) {
|
||||
print_usage(filename);
|
||||
print_help(filename);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[argi], "--version") == 0) {
|
||||
printf("mstpcap %s\n", BACNET_VERSION_TEXT);
|
||||
printf("Copyright (C) 2011 by Steve Karg\n"
|
||||
"This is free software; see the source for copying conditions.\n"
|
||||
"There is NO warranty; not even for MERCHANTABILITY or\n"
|
||||
"FITNESS FOR A PARTICULAR PURPOSE.\n");
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[argi], "--scan") == 0) {
|
||||
argi++;
|
||||
if (argi >= argc) {
|
||||
printf("An file name must be provided.\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Scanning %s\n", argv[argi]);
|
||||
/* perform statistics on the file */
|
||||
if (test_global_header(argv[2])) {
|
||||
if (test_global_header(argv[argi])) {
|
||||
while (read_received_packet(mstp_port)) {
|
||||
packet_count++;
|
||||
fprintf(stderr, "\r%u packets", (unsigned) packet_count);
|
||||
fprintf(stderr, "\r%u packets",
|
||||
(unsigned) packet_count);
|
||||
}
|
||||
if (packet_count) {
|
||||
packet_statistics_print();
|
||||
@@ -959,20 +1018,70 @@ int main(
|
||||
} else {
|
||||
fprintf(stderr, "File header does not match.\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[argi], "--extcap-interfaces") == 0) {
|
||||
RS485_Print_Ports();
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[argi], "--extcap-dlts") == 0) {
|
||||
argi++;
|
||||
if (argi >= argc) {
|
||||
printf("An interface must be provided.\n");
|
||||
return 0;
|
||||
}
|
||||
printf("dlt {number=%u}{name=BACnet MS/TP}"
|
||||
"{display=BACnet MS/TP}\n",
|
||||
DLT_BACNET_MS_TP);
|
||||
Exit_Requested = true;
|
||||
}
|
||||
if (strcmp(argv[argi], "--extcap-config") == 0) {
|
||||
printf("arg {number=0}{call=--baud}{display=Baud Rate}"
|
||||
"{tooltip=Serial port baud rate in bits per second}"
|
||||
"{type=selector}\n");
|
||||
printf("value {arg=0}{value=9600}{display=9600}{default=false}\n");
|
||||
printf("value {arg=0}{value=19200}{display=19200}{default=false}\n");
|
||||
printf("value {arg=0}{value=38400}{display=38400}{default=true}\n");
|
||||
printf("value {arg=0}{value=57600}{display=57600}{default=false}\n");
|
||||
printf("value {arg=0}{value=76800}{display=76800}{default=false}\n");
|
||||
printf("value {arg=0}{value=115200}{display=115200}{default=false}\n");
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[argi], "--capture") == 0) {
|
||||
/* do nothing - fall through and start running! */
|
||||
}
|
||||
if (strcmp(argv[argi], "--extcap-interface") == 0) {
|
||||
argi++;
|
||||
if (argi >= argc) {
|
||||
printf("An interface must be provided or "
|
||||
"the selection must be displayed.\n");
|
||||
return 0;
|
||||
}
|
||||
RS485_Set_Interface(argv[argi]);
|
||||
}
|
||||
if (strcmp(argv[argi], "--baud") == 0) {
|
||||
argi++;
|
||||
if (argi >= argc) {
|
||||
printf("A baud rate must be provided.\n");
|
||||
return 0;
|
||||
}
|
||||
my_baud = strtol(argv[argi], NULL, 0);
|
||||
RS485_Set_Baud_Rate(my_baud);
|
||||
}
|
||||
if (strcmp(argv[argi], "--fifo") == 0) {
|
||||
argi++;
|
||||
if (argi >= argc) {
|
||||
printf("A named pipe must be provided.\n");
|
||||
return 0;
|
||||
}
|
||||
named_pipe_create(argv[argi]);
|
||||
}
|
||||
}
|
||||
if (argc > 1) {
|
||||
RS485_Set_Interface(argv[1]);
|
||||
} else {
|
||||
#if defined(_WIN32)
|
||||
print_com_ports();
|
||||
if (Exit_Requested) {
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
if (argc > 2) {
|
||||
my_baud = strtol(argv[2], NULL, 0);
|
||||
RS485_Set_Baud_Rate(my_baud);
|
||||
if (argc <= 1) {
|
||||
RS485_Print_Ports();
|
||||
return 0;
|
||||
}
|
||||
atexit(cleanup);
|
||||
RS485_Initialize();
|
||||
@@ -985,9 +1094,6 @@ int main(
|
||||
#else
|
||||
signal_init();
|
||||
#endif
|
||||
if (argc > 3) {
|
||||
named_pipe_create(argv[3]);
|
||||
}
|
||||
filename_create_new();
|
||||
/* run forever */
|
||||
for (;;) {
|
||||
|
||||
Reference in New Issue
Block a user