The mstpscap. c file is used to capture packets on the MS/TP protocol from the serial port. The format for testing is: mstsnap [Serial] [baud] [network]
The default parameters are serial port/dev/ttyusb0, baud rate is 38400, and eth0.
# Include <stddef. h>
# Include <stdint. h>
# Include <stdio. h>
# Include <stdlib. h>
# Include <string. h>
# Include <errno. h>
/* OS specific include */
# Include "net. H"
# Include "timer. H"
/* Local primary des */
# Include "bytes. H"
# Include "rs485.h"
# Include "CRC. H"
# Include "MSTP. H"
# Include "dlmstp. H"
# Include "mstptext. H"
# Include "bacint. H"
/** @ File Linux/mstpsnap. c example application testing BACnet MS/TP on Linux .*/
# Ifndef Max
# Define max (A, B) (a)> (B ))? (A): (B ))
# Define min (A, B) (a) <(B ))? (A): (B ))
# Endif
/* Local port data-shared with RS-485 */
Static volatile struct mstp_port_struct_t mstp_port;
/* Buffers needed by MSTP port struct */
Static uint8_t rxbuffer [max_mpdu];
Static uint8_t txbuffer [max_mpdu];
Static uint16_t timer_silence (
Void)
{
Uint32_t delta_time = 0;
Delta_time = timer_milliseconds (timer_silence );
If (delta_time> 0 xFFFF ){
Delta_time = 0 xFFFF;
}
Return (uint16_t) delta_time;
}
Static void timer_silence_reset (
Void)
{
Timer_reset (timer_silence );
}
/* Functions used by the MS/TP state machine to put or get data */
Uint16_t mstp_put_receive (
Volatile struct mstp_port_struct_t * mstp_port)
{
(Void) mstp_port;
Return 0;
}
/* For the MS/TP state machine to use for getting data to send */
/* Return: Amount of PDU data */
Uint16_t mstp_get_send (
Volatile struct mstp_port_struct_t * mstp_port,
Unsigned timeout)
{/* Milliseconds to wait for a packet */
(Void) mstp_port;
(Void) Timeout;
Return 0;
}
Uint16_t mstp_get_reply (
Volatile struct mstp_port_struct_t * mstp_port,
Unsigned timeout)
{/* Milliseconds to wait for a packet */
(Void) mstp_port;
(Void) Timeout;
Return 0;
}
Static int network_init (
Const char * Name,
Int Protocol)
{
/* Check to see if we are being run as root */
If (getuid ()! = 0) {// The function returns the real User ID of a calling program. Generally, this function is called successfully. Getuid = 0 indicates the root user.
Fprintf (stderr, "requires root priveleges. \ n ");
Return-1;
}
Int sockfd = socket (pf_packet, sock_raw, htons (Protocol); // get the original IP package. htons gets the network byte order (large-end mode) and uses the big-end mode for unified transmission.
If (sockfd =-1 ){
Perror ("unable to create socket ");
Return sockfd;
}
Struct ifreq IFR;
// Obtain the IP address and MAC address
Memset (& IFR, 0, sizeof (IFR ));
Strncpy (IFR. ifr_name, name, strlen (name ));
If (IOCTL (sockfd, siocgifindex, & IFR) =-1) {// obtain and print the NIC address
Perror ("unable to get interface Index ");
Return-1;
}
Struct sockaddr_ll sll;
// Local address
Memset (& sll, 0, sizeof (SLL ));
SLL. sll_family = af_packet;
SLL. sll_ifindex = IFR. ifr_ifindex;
SLL. sll_protocol = htons (Protocol );
If (BIND (sockfd, (struct sockaddr *) & sll, sizeof (SLL) =-1) {// bind a socket
Perror ("unable to bind socket ");
Return-1;
}
Return sockfd;
}
Static void snap_received_packet (
Volatile struct mstp_port_struct_t * mstp_port,
Int sockfd)
{
Uint16_t mtu_len = 0;/* Number of ETS ets of packet saved in file */
Unsigned I = 0;/* counter */
Static uint8_t MTU [1500] = {0}; // for physical layer implementation and other reasons, the length of an Ethernet frame is generally less than 1500 bytes.
Uint16_t max_data = 0;
MTU [0] = 0;
MTU [1] = 0;
MTU [2] = 0;
MTU [3] = 0;
MTU [4] = 0;
MTU [5] = mstp_port-> destinationaddress;
MTU [6] = 0;
MTU [7] = 0;
MTU [8] = 0;
MTU [9] = 0;
MTU [10] = 0;
MTU [11] = mstp_port-> sourceaddress;
/* Length-12, 13 */
MTU [14] = 0xaa;/* DSAP for SNAP */
MTU [15] = 0xaa;/* SSAP for SNAP */
MTU [16] = 0x03;/* control field for SNAP */
MTU [17] = 0x00;/* Organization Code: cimetrics */
MTU [18] = 0x10;/* Organization Code: cimetrics */
MTU [19] = 0x90;/* Organization Code: cimetrics */
MTU [20] = 0x00;/* protocol id */
MTU [21] = 0x01;/* protocol id */
MTU [22] = 0x00;/* Delta time */
MTU [23] = 0x00;/* Delta time */
MTU [24] = 0x80;/* unknown byte */
MTU [25] = mstp_port-> frametype;
MTU [26] = mstp_port-> destinationaddress;
MTU [27] = mstp_port-> sourceaddress;
MTU [28] = hi_byte (mstp_port-> datalength );
MTU [29] = lo_byte (mstp_port-> datalength );
MTU [30] = mstp_port-> headercrcactual;
Mtu_len = 31;
If (mstp_port-> datalength) {// store data from the input cache and datacrcactual (first high and then low order)
Max_data = min (mstp_port-> inputbuffersize, mstp_port-> datalength );
For (I = 0; I <max_data; I ++ ){
MTU [31 + I] = mstp_port-> inputbuffer [I];
}
MTU [31 + max_data] = mstp_port-> datacrcactualmsb;
MTU [31 + max_data + 1] = mstp_port-> datacrcactuallsb;
Mtu_len + = (max_data + 2 );
}
/* Ethernet length is data only-not address or length bytes */
Encode_unsigned16 (& MTU [12], mtu_len-14); // encode the integer type
(Void) write (sockfd, & MTU [0], mtu_len );
}
Static void cleanup (
Void)
{
}
# If (! Defined (_ Win32 ))
Static void sig_int (
Int signo)
{
(Void) signo;
Cleanup ();
Exit (0 );
}
Void signal_init (
Void)
{
Signal (SIGINT, sig_int );
Signal (sighup, sig_int );
Signal (sigterm, sig_int );
}
# Endif
/* Simple test to packetize the data and print it */
Int main (INT argc, char * argv []) // The main function is used to run root # mstpsnap/dev/tty/usb0 38400 eth0 on a Linux terminal.
{
Volatile struct mstp_port_struct_t * mstp_port;
Long my_baud = 38400;
Uint32_t packet_count = 0;
Int sockfd =-1;
Char * my_interface = "eth0 ";
/* Mimic our pointer in the state machine */
Mstp_port = & mstp_port;
If (argc> 1) & (strcmp (argv [1], "-- Help") = 0 )){
Printf ("mstsnap [Serial] [baud] [network] \ r \ n"
& Quot; captures MS/TP packets from a serial interface \ r \ n & quot"
"And sends them to a network interface using SNAP \ r \ n"
"Protocol packets (mimics cimetrics U + 4 packet). \ r \ n" "\ r \ n"
"Command line options: \ r \ n" "[Serial]-serial interface. \ r \ n"
"Defaults to/dev/ttyusb0. \ r \ n"
"[Baud]-baud rate. 9600,192 00, 38400,576 00, 115200 \ r \ n"
"Defaults to 38400. \ r \ n" "[network]-network interface. \ r \ n"
"Defaults to eth0. \ r \ n """);
Return 0;
}
/* Initialize our interface */
If (argc> 1 ){
Rs485_set_interface (argv [1]);
}
If (argc> 2 ){
My_baud = strtol (argv [2], null, 0); // convert argv [2] to decimal form
}
If (argc> 3 ){
My_interface = argv [3];
}
Sockfd = network_init (my_interface, eth_p_all );
If (sockfd =-1 ){
Return 1;
} // Set some content parameters in the MS/TP protocol. This part requires familiarity with the MS/TP protocol content. For more information, see <principles and control of smart building BACnet>
Rs485_set_baud_rate (my_baud );
Rs485_initialize ();
Mstp_port.inputbuffer = & rxbuffer [0];
Mstp_port.inputbuffersize = sizeof (rxbuffer );
Mstp_port.outputbuffer = & txbuffer [0];
Mstp_port.outputbuffersize = sizeof (txbuffer );
Mstp_port.this_station = 127;
Mstp_port.nmax_info_frames = 1;
Mstp_port.nmax_master = 127;
Mstp_port.silencetimer = timer_silence;
Mstp_port.silencetimerreset = timer_silence_reset;
Mstp_init (mstp_port );
Fprintf (stdout, "mstpcap: using % s for capture at % ld bps. \ n ",
Rs485_interface (), (long) rs485_get_baud_rate ());
Atexit (cleanup );
# If defined (_ Win32)
Setconsolemode (getstdhandle (std_input_handle), enable_processed_input );
Setconsolectrlhandler (phandler_routine) ctrlchandler, true );
# Else
Signal_init ();
# Endif
/* Run forever */
For (;;){
Rs485_check_uart_data (mstp_port );
Mstp_receive_frame_fsm (mstp_port );
/* Process the data portion of the frame */
If (mstp_port-> receivedvalidframe ){
Mstp_port-> receivedvalidframe = false;
Snap_received_packet (mstp_port, sockfd );
Packet_count ++;
} Else if (mstp_port-> receivedinvalidframe ){
Mstp_port-> receivedinvalidframe = false;
Fprintf (stderr, "receivedinvalidframe \ n ");
Snap_received_packet (mstp_port, sockfd );
Packet_count ++;
}
If (! (Packet_count % 100 )){
Fprintf (stdout, "\ r % Hu packets", packet_count );
}
}
Return 0;
}