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:
skarg
2015-07-14 20:31:32 +00:00
parent edcf8404d7
commit b4ad2c2729
5 changed files with 216 additions and 78 deletions
+184 -78
View File
@@ -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 (;;) {
+8
View File
@@ -624,6 +624,14 @@ void RS485_Initialize(
printf("=success!\n");
}
void RS485_Print_Ports(void)
{
/* note: format for Wireshark ExtCap */
//printf("interface {value=/dev/ttyUSB%u}"
// "{display=MS/TP Capture on /dev/ttyUSB%u}\n", i, i);
/* FIXME: add code to print ports */
}
#ifdef TEST_RS485
#include <string.h>
int main(
+2
View File
@@ -67,6 +67,8 @@ extern "C" {
void RS485_Cleanup(
void);
void RS485_Print_Ports(
void);
#ifdef __cplusplus
}
+20
View File
@@ -489,6 +489,26 @@ void RS485_Check_UART_Data(
}
}
/*************************************************************************
* Description: print available COM ports
* Returns: none
* Notes: none
**************************************************************************/
void RS485_Print_Ports(
void)
{
unsigned i = 0;
/* try to open all 255 COM ports */
for (i = 1; i < 256; i++) {
if (RS485_Interface_Valid(i)) {
/* note: format for Wireshark ExtCap */
printf("interface {value=COM%u}"
"{display=BACnet MS/TP on COM%u}\n", i, i);
}
}
}
#ifdef TEST_RS485
#include "mstpdef.h"
+2
View File
@@ -70,6 +70,8 @@ extern "C" {
bool RS485_Interface_Valid(
unsigned port_number);
void RS485_Print_Ports(
void);
#ifdef __cplusplus