00001
00058 #define VERSION "1.0"
00059
00063 #define PROCESS_VLAN
00064
00067 #define PROCESS_MPLS
00068
00069 #define _GNU_SOURCE
00070 #include <stdio.h>
00071 #include <stdlib.h>
00072 #include <unistd.h>
00073 #include <pcap.h>
00074 #include <netinet/ip.h>
00075 #include <netinet/ip6.h>
00076 #include <netinet/ether.h>
00077 #include <poll.h>
00078 #include <string.h>
00079 #include <errno.h>
00080 #include <signal.h>
00081
00082
00083 #include <openssl/md5.h>
00084
00085 #include <flowmonexp/plugin_input.h>
00086
00087 #include "protocols.h"
00088
00125 #define PCAP_SIZE 1500
00126 #define PCAP_TIMEOUT 500
00131 unsigned int __attribute__((used))plugin_type = (PLUGIN_TYPE_INPUT);
00132
00136 #define PRINT(format,args...)
00137
00138
00142 #define PRINTERR(format,args...) fprintf(stderr,format,##args)
00143
00147 #define PRINTWARN(format,args...) fprintf(stderr,format,##args)
00148
00153 typedef struct {
00154 pcap_t *pcap;
00155 int data_offset;
00156 unsigned int counter;
00157 int offline;
00158 } bacnet_input_private_t;
00159
00163 typedef struct {
00164 uint16_t ethertype;
00165 uint8_t control;
00166 uint8_t hops;
00167 uint8_t msg_type;
00168 uint16_t vendor_id;
00169 uint16_t snet;
00170 uint16_t dnet;
00171 uint8_t slen;
00172 uint8_t dlen;
00173 uint8_t sadr[7];
00174 uint8_t dadr[7];
00175 } bacnet_record_t;
00176
00187 int parse_eth (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr);
00188
00199 int parse_llc (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr);
00200
00211 int parse_bacnet_vlc (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr);
00212
00224 int parse_bacnet_ip (uint16_t ethtype, unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr);
00225
00236 int parse_bacnet (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr);
00237
00241 static plugin_desc_t plugin_desc = {
00242 "input-bacnet",
00243 "Version " VERSION
00244 "\nflowmonexp input plugin processing BACnet traffic\
00245 \nOne of input parameters:\
00246 \n\t- read data from stdin\
00247 \n\tfile read data from pcap file\
00248 \n\t@if read data from pcap interface if\
00249 \nSeparated by ',' there can be specified filename containing BPF filter(s)",
00250 sizeof(bacnet_record_t),
00251 0
00252 };
00253
00258 plugin_desc_t *plugin_input_desc()
00259 {
00260 return (&plugin_desc);
00261 }
00262
00271 int validity_control(void *self, flow_record_t *r)
00272 {
00273 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00274 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00275 if (pr->ethertype == BACNET_ETH_TYPE || pr->ethertype == BACNET_IP_TYPE) {
00276 return (1);
00277 } else {
00278 return (0);
00279 }
00280 }
00281
00290 int validity_fail(void *self, flow_record_t *r)
00291 {
00292 return (0);
00293 }
00294
00303 int validity_ethertype(void *self, flow_record_t *r)
00304 {
00305 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00306 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00307 if (pr->ethertype != 0) {
00308 return (1);
00309 } else {
00310 return (0);
00311 }
00312 }
00313
00322 int validity_dst(void *self, flow_record_t *r)
00323 {
00324 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00325 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00326 if (pr->control & BACNET_CTRL_DST_MASK) {
00327 return (1);
00328 } else {
00329 return (0);
00330 }
00331 }
00332
00341 int validity_dstadr(void *self, flow_record_t *r)
00342 {
00343 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00344 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00345 if (validity_dst (self, r) && pr->dlen > 0) {
00346 return (1);
00347 } else {
00348 return (0);
00349 }
00350 }
00351
00360 int validity_src(void *self, flow_record_t *r)
00361 {
00362 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00363 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00364 if (pr->control & BACNET_CTRL_SRC_MASK) {
00365 return (1);
00366 } else {
00367 return (0);
00368 }
00369 }
00370
00379 int validity_srcadr(void *self, flow_record_t *r)
00380 {
00381 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00382 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00383 if (validity_src (self, r) && pr->slen > 0) {
00384 return (1);
00385 } else {
00386 return (0);
00387 }
00388 }
00389
00398 int validity_msg_type(void *self, flow_record_t *r)
00399 {
00400 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00401 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00402 if (pr->control & BACNET_CTRL_MSGTYPE_MASK) {
00403 return (1);
00404 } else {
00405 return (0);
00406 }
00407 }
00408
00417 int value_length_8(void *self, flow_record_t *r)
00418 {
00419 return (sizeof(uint8_t));
00420 }
00421
00430 int value_length_16(void *self, flow_record_t *r)
00431 {
00432 return (sizeof(uint16_t));
00433 }
00434
00443 int value_length_dadr(void *self, flow_record_t *r)
00444 {
00445 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00446 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00447 return (pr->dlen);
00448 }
00449
00458 int value_length_sadr(void *self, flow_record_t *r)
00459 {
00460 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00461 bacnet_record_t *pr = PLUGIN_DATA(r,p->data_offset);
00462 return (pr->slen);
00463 }
00464
00473 void value_fill_ethertype(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00474 {
00475 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00476 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00477 record_universal_get (dst, &(pr->ethertype), 0, sizeof(uint16_t), len, to_network_byte_order);
00478 }
00479
00488 void value_fill_control(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00489 {
00490 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00491 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00492 record_universal_get (dst, &(pr->control), 0, sizeof(uint8_t), len, to_network_byte_order);
00493 }
00494
00503 void value_fill_hops(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00504 {
00505 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00506 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00507 record_universal_get (dst, &(pr->hops), 0, sizeof(uint8_t), len, to_network_byte_order);
00508 }
00509
00518 void value_fill_msg_type(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00519 {
00520 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00521 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00522 record_universal_get (dst, &(pr->msg_type), 0, sizeof(uint8_t), len, to_network_byte_order);
00523 }
00524
00533 void value_fill_vendor_id(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00534 {
00535 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00536 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00537 record_universal_get (dst, &(pr->vendor_id), 0, sizeof(uint16_t), len, to_network_byte_order);
00538 }
00539
00548 void value_fill_dnet(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00549 {
00550 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00551 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00552 record_universal_get (dst, &(pr->dnet), 0, sizeof(uint16_t), len, to_network_byte_order);
00553 }
00554
00563 void value_fill_dadr(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00564 {
00565 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00566 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00567 record_universal_get (dst, &(pr->dadr[0]), 0, pr->dlen, len, to_network_byte_order);
00568 }
00569
00578 void value_fill_snet(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00579 {
00580 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00581 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00582 record_universal_get (dst, &(pr->snet), 0, sizeof(uint16_t), len, to_network_byte_order);
00583 }
00584
00593 void value_fill_sadr(void *self, flow_record_t *record, void *dst, int len, int to_network_byte_order)
00594 {
00595 bacnet_input_private_t *p = (bacnet_input_private_t*) self;
00596 bacnet_record_t *pr = PLUGIN_DATA(record,p->data_offset);
00597 record_universal_get (dst, &(pr->sadr[0]), 0, pr->slen, len, to_network_byte_order);
00598 }
00599
00606 void plugin_input_getter_init(void *plugin_private, flow_record_getter_t **getter_list)
00607 {
00608 PRINT("getter init started\n");
00609 getter_add (getter_list, "ETHERTYPE", sizeof(uint16_t), plugin_private, &validity_ethertype, &value_length_16, &value_fill_ethertype);
00610 getter_add (getter_list, "BACNET_CONTROL", sizeof(uint8_t), plugin_private, &validity_control, &value_length_8, &value_fill_control);
00611 getter_add (getter_list, "BACNET_HOP_COUNT", sizeof(uint8_t), plugin_private, &validity_dst, &value_length_8, &value_fill_hops);
00612 getter_add (getter_list, "BACNET_MESSAGE_TYPE", sizeof(uint8_t), plugin_private, &validity_msg_type, &value_length_8, &value_fill_msg_type);
00613 getter_add (getter_list, "BACNET_VENDOR_ID", sizeof(uint16_t), plugin_private, &validity_fail, &value_length_16, &value_fill_vendor_id);
00614 getter_add (getter_list, "BACNET_SNET", sizeof(uint16_t), plugin_private, &validity_src, &value_length_16, &value_fill_snet);
00615 getter_add (getter_list, "BACNET_DNET", sizeof(uint16_t), plugin_private, &validity_dst, &value_length_16, &value_fill_dnet);
00616 getter_add (getter_list, "BACNET_SADR", -1, plugin_private, &validity_srcadr, &value_length_sadr, &value_fill_sadr);
00617 getter_add (getter_list, "BACNET_DADR", -1, plugin_private, &validity_dstadr, &value_length_dadr, &value_fill_dadr);
00618 PRINT("getter init finished\n");
00619 }
00620
00631 void *plugin_input_init(char *params, int full_packet, int data_offset)
00632 {
00633 bacnet_input_private_t *retval;
00634 char errbuf[PCAP_ERRBUF_SIZE];
00635 char *filename, *next_param = NULL, *line = NULL;
00636 struct bpf_program filter;
00637 FILE *filter_file;
00638 size_t size;
00639
00640
00641 retval = malloc (sizeof(bacnet_input_private_t));
00642 if (!retval) {
00643 return (NULL);
00644 }
00645
00646 retval->offline = 1;
00647 if (params != NULL) {
00648 next_param = strchr (params, ',');
00649 if (next_param != NULL) {
00650 next_param[0] = 0;
00651 next_param++;
00652 }
00653 }
00654
00655
00656 if (!params || params[0] == '-' || params[0] == 0) {
00657
00658 filename = strdup ("-");
00659 } else {
00660 if (params[0] == '@') {
00661
00662 retval->offline = 0;
00663 filename = strdup (¶ms[1]);
00664 } else {
00665
00666 retval->offline = 1;
00667 filename = strdup (params);
00668 }
00669 }
00670
00671
00672 if (retval->offline == 1) {
00673 PRINT ("BACnet plugin opens file %s\n", filename);
00674 retval->pcap = pcap_open_offline (filename, errbuf);
00675 } else {
00676 PRINT ("BACnet plugin opens live device %s\n", filename);
00677 retval->pcap = pcap_open_live (filename, PCAP_SIZE, 1, 0, errbuf);
00678 }
00679
00680 free (filename);
00681 if (retval->pcap == NULL) {
00682 PRINTERR ( "Unable to init pcap: %s\n", errbuf);
00683 free (retval);
00684 return (NULL);
00685 }
00686
00687
00688 while (next_param != NULL) {
00689 PRINT ("setting BPF ");
00690 params = next_param;
00691 next_param = strchr (params, ',');
00692 if (next_param != NULL) {
00693 next_param[0] = 0;
00694 next_param++;
00695 }
00696
00697 PRINT ("from file %s\n", params);
00698 if ((filter_file = fopen(params, "r")) == NULL) {
00699 PRINTERR ("Setting BPF filter failed: %s\n", strerror (errno));
00700 free (retval);
00701 return (NULL);
00702 }
00703 line = NULL;
00704 while (getline (&line, &size, filter_file) > 0) {
00705 PRINT ("Filtering with BPF: %s\n", line);
00706 if (pcap_compile (retval->pcap, &filter, line, 1, 0) != 0) {
00707 PRINTERR ("Compiling BPF filter failed: %s\n", pcap_geterr (retval->pcap));
00708 free (retval);
00709 return (NULL);
00710 }
00711 if (pcap_setfilter (retval->pcap, &filter)) {
00712 PRINTERR ("Setting BPF filter failed: %s\n", pcap_geterr (retval->pcap));
00713 free (retval);
00714 return (NULL);
00715 }
00716 free (line);
00717 line = NULL;
00718 }
00719
00720 fclose (filter_file);
00721 }
00722 retval->data_offset = data_offset;
00723 retval->counter = 0;
00724 return (retval);
00725 }
00726
00727 static MD5_CTX md5;
00728
00747 #ifdef DOXYGEN
00748 uint64_t plugin_input_get_final_flow(void *plugin_private, flow_record_t * record);
00749 uint64_t plugin_input_get_flow(void *plugin_private, flow_record_t * record);
00750 #endif
00751
00752 #ifdef SPF
00753
00754 #ifndef DOXYGEN
00755 #define GET_FAILED 1
00756 #endif
00757 uint64_t plugin_input_get_final_flow(void *plugin_private, flow_record_t * record)
00758 {
00759 #else
00760 #ifndef DOXYGEN
00761 #define GET_FAILED 0
00762 #endif
00763 uint64_t plugin_input_get_flow(void *plugin_private, flow_record_t * record)
00764 {
00765 #endif
00766 bacnet_input_private_t *p = (bacnet_input_private_t*) plugin_private;
00767 bacnet_record_t *precord = PLUGIN_DATA(record,p->data_offset);
00768 struct pcap_pkthdr hdr;
00769 unsigned char *buf;
00770 int datalink;
00771 uint64_t hash[2];
00772 int ret;
00773
00774 memset ((void*) precord, 0, sizeof(bacnet_record_t));
00775
00776 PRINT("packet No: %d\n", ++(p->counter));
00777
00778
00779 buf = (unsigned char*) pcap_next (p->pcap, &hdr);
00780
00781
00782 if ((p->offline == 1) && (buf == NULL)) {
00783
00784 sleep (5);
00785 raise (SIGQUIT);
00786 sleep (5);
00787 return GET_FAILED;
00788 }
00789
00790
00791 record->flow_end = record->flow_start = ((uint64_t) hdr.ts.tv_sec * 1000 * 1000 * 1000) + ((uint64_t) hdr.ts.tv_usec * 1000);
00792
00793 record->flow_packets = 1;
00794
00795 record->flow_octets = hdr.len;
00796
00797
00798 datalink = pcap_datalink (p->pcap);
00799
00800 MD5_Init (&md5);
00801 if (datalink == DLT_EN10MB) {
00802
00803 ret = parse_eth (buf, (uint32_t) hdr.caplen, record, precord);
00804 PRINT("parse_eth returned %d\n", ret);
00805 if (ret != EXIT_SUCCESS) {
00806 return GET_FAILED;
00807 } else {
00808 #ifdef SPF
00809 return 0;
00810 #else
00811
00812 MD5_Final ((unsigned char *) hash, &md5);
00813 return ((hash[0] ^ hash[1]) | FLOW_OK_BIT);
00814 #endif
00815 }
00816 }
00817
00818 return GET_FAILED;
00819 }
00820
00831 int parse_eth (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr)
00832 {
00833 uint16_t ethtype;
00834 uint32_t orig_caplen = caplen;
00835 uint64_t internal_hash = 0;
00836 struct ethhdr *eth;
00837 unsigned char* next_hdr = buf;
00838 int ret = EXIT_SUCCESS;
00839 vlan_t *vlan;
00840 uint32_t bytes = record->flow_octets;
00841
00842 if (caplen < ETH_HLEN
00843 )
00844 return (EXIT_FAILURE);
00845
00846 eth = (struct ethhdr*) buf;
00847 ethtype = ntohs (eth->h_proto);
00848
00849 if (ethtype <= ETH_DATA_LEN) {
00850
00851
00852 PRINT("LLC instead of 802.3\n");
00853 return (parse_llc (next_hdr + ETH_HLEN, caplen - ETH_HLEN, record, pr));
00854 } else {
00855 PRINT("802.3\n");
00856
00857
00858 memcpy (record->l2.src_mac, eth->h_source, ETH_ALEN);
00859 memcpy (record->l2.dst_mac, eth->h_dest, ETH_ALEN);
00860 MD5_Update (&md5, &(record->l2), 2 * ETH_ALEN);
00861
00862
00863 next_hdr += ETH_HLEN;
00864 caplen -= ETH_HLEN;
00865 }
00866
00867 recurse:
00868
00869 switch (ethtype) {
00870 case ETH_P_IPV6:
00871 case ETH_P_IP:
00872 PRINT("IP, %p\n", buf);
00873
00874 pr->ethertype = ethtype;
00875 if ((internal_hash = record_process_packet (buf, (int) orig_caplen, record)) == 0) {
00876 return (EXIT_FAILURE);
00877 }
00878
00879 if ((record->l4.protocol == IPPROTO_UDP) && (record->l4.src_port == BACNET_UDP_PORT) && (record->l4.dst_port == BACNET_UDP_PORT)) {
00880
00881 parse_bacnet_ip (ethtype, next_hdr, caplen, record, pr);
00882 }
00883 MD5_Update (&md5, &internal_hash, 8);
00884
00885
00886
00887
00888
00889
00890 record->flow_octets = bytes;
00891
00892 break;
00893 case ETH_P_8021Q:
00894 case _ETH_P_8021QINQ:
00895 case _ETH_P_8021QINQ_DOUBLE:
00896 case _ETH_P_8021QINQ_TRIPPLE:
00897 case _ETH_P_8021AD:
00898 PRINT("VLAN\n");
00899 if (caplen < VLAN_HLEN) {
00900 return (EXIT_FAILURE);
00901 }
00902
00903
00904 if ((vlan = record_vlan (record)) != NULL) {
00905 if (vlan->count < VLAN_MAX) {
00906 PRINT("VLAN count: %d\n", vlan->count);
00907 vlan->id[vlan->count] = htons((*(uint16_t *) next_hdr) & VLAN_ID_MASK);
00908 MD5_Update (&md5, &(vlan->id[vlan->count]), 2);
00909 vlan->count++;
00910 }
00911 }
00912
00913
00914
00915
00916
00917
00918
00919 ethtype = ntohs (*(uint16_t *) (next_hdr + 2));
00920 next_hdr += VLAN_HLEN;
00921 caplen -= VLAN_HLEN;
00922
00923
00924 goto recurse;
00925 case ETH_P_MPLS_UC:
00926 case ETH_P_MPLS_MC:
00927 PRINT("MPLS\n");
00928 pr->ethertype = ethtype;
00929 ret = EXIT_SUCCESS;
00930
00931 break;
00932 default:
00933 if (ethtype <= ETH_DATA_LEN) {
00934
00935 ret = parse_llc (next_hdr, caplen, record, pr);
00936 } else {
00937
00938 pr->ethertype = ethtype;
00939 ret = EXIT_SUCCESS;
00940 }
00941 break;
00942 }
00943
00944 return (ret);
00945
00946 }
00947
00959 int parse_bacnet_ip (uint16_t ethtype, unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr)
00960 {
00961 struct ip *ip;
00962 struct ip6_hdr *ip6;
00963 unsigned char* bacnet_vlc = buf;
00964 int ret = 1;
00965
00966 switch (ethtype) {
00967 case ETH_P_IPV6:
00968 PRINT ("BACnet over IPv6\n");
00969 ip6 = (struct ip6_hdr*) buf;
00970
00971 break;
00972 case ETH_P_IP:
00973 ip = (struct ip*) buf;
00974 bacnet_vlc += ((ip->ip_hl * 4) + UDP_HDR_SIZE);
00975 caplen -= ((ip->ip_hl * 4) + UDP_HDR_SIZE);
00976 PRINT ("BACnet over IPv4, %p (%d)\n", buf, ip->ip_hl * 4);
00977
00978 ret = parse_bacnet_vlc (bacnet_vlc, caplen, record, pr);
00979 break;
00980 default:
00981 return 1;
00982 break;
00983 }
00984
00985 return ret;
00986 }
00987
00998 int parse_bacnet_vlc (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr)
00999 {
01000 int bvlc_length;
01001 uint8_t bvlc_function = buf[1];
01002
01003 PRINT ("BVLC, %p\n", buf);
01004 pr->ethertype = BACNET_IP_TYPE;
01005
01006 if (bvlc_function > 0x08) {
01007
01008
01009
01010
01011
01012
01013 bvlc_length = 4;
01014 } else if (bvlc_function == 0x04) {
01015
01016 bvlc_length = 10;
01017 } else {
01018
01019
01020
01021
01022
01023 return (EXIT_SUCCESS);
01024 }
01025 return (parse_bacnet (buf + bvlc_length, caplen - bvlc_length, record, pr));
01026 }
01027
01038 int parse_llc (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr)
01039 {
01040 int hlen = 0;
01041
01042
01043 if ((buf[0] & LLC_SAP_MASK) != LLC_SAP_BACNET) {
01044 PRINT ("Unsupported LLC\n");
01045 return (EXIT_FAILURE);
01046 }
01047
01048
01049
01050
01051
01052
01053
01054 hlen = ((buf[2] & 0x03) == 0x03) ? 3 : 4;
01055 PRINT ("LLC type %x\n",buf[2] & 0x03);
01056
01057
01058 pr->ethertype = (BACNET_ETH_TYPE);
01059
01060 return (parse_bacnet (buf + hlen, caplen - hlen, record, pr));
01061 }
01062
01073 int parse_bacnet (unsigned char* buf, uint32_t caplen, flow_record_t *record, bacnet_record_t *pr)
01074 {
01075 PRINT("BACnet, %p\n", buf);
01076 uint8_t *data;
01077 int i, len;
01078
01079 struct bacnet_npdu *npdu = (struct bacnet_npdu*) buf;
01080 PRINT("\tVersion: %d\n", npdu->version);
01081
01082 PRINT("\tControl: %x\n", npdu->control);
01083 pr->control = npdu->control;
01084
01085 data = &(npdu->data[0]);
01086
01087 if (npdu->control & BACNET_CTRL_DST_MASK) {
01088 PRINT("\tDNET: %d\n", ntohs(*(uint16_t*)&data[0]));
01089 pr->dnet = ntohs (*(uint16_t*) &data[0]);
01090 MD5_Update (&md5, &(pr->dnet), sizeof(uint16_t));
01091
01092 PRINT("\tDLEN: %d\n", data[2]);
01093 pr->dlen = data[2];
01094 len = 3;
01095 if (data[2] > 0) {
01096 PRINT ("\tDADR: ");
01097 for (i = 0; i < data[2]; i++) {
01098 PRINT("%02X",data[3+i]);
01099 len++;
01100 }PRINT ("\n");
01101 memcpy (&(pr->dadr[0]), &(data[3]), data[2]);
01102 MD5_Update (&md5, &(pr->dadr), pr->dlen);
01103 }
01104 data = &(data[len]);
01105 }
01106
01107 if (npdu->control & BACNET_CTRL_SRC_MASK) {
01108 PRINT("\tSNET: %d\n", ntohs(*(uint16_t*)&data[0]));
01109 pr->snet = ntohs (*(uint16_t*) &data[0]);
01110 MD5_Update (&md5, &(pr->snet), sizeof(uint16_t));
01111
01112 PRINT("\tSLEN: %d\n", data[2]);
01113 pr->slen = data[2];
01114 len = 3;
01115 if (data[2] > 0) {
01116 PRINT ("\tSADR: ");
01117 for (i = 0; i < data[2]; i++) {
01118 PRINT("%02X",data[3+i]);
01119 len++;
01120 }PRINT ("\n");
01121 memcpy (&(pr->sadr[0]), &(data[3]), data[2]);
01122 PRINT ("\tSADR: ");
01123 for (i = 0; i < pr->slen; i++) {
01124 PRINT("%02X",pr->sadr[i]);
01125 }PRINT ("\n");
01126 MD5_Update (&md5, &(pr->sadr), pr->slen);
01127 }
01128 data = &(data[len]);
01129 }
01130
01131 if (npdu->control & BACNET_CTRL_DST_MASK) {
01132 PRINT ("\tHOP COUNT: %d\n", data[0]);
01133 pr->hops = data[0];
01134 data = &(data[1]);
01135 }
01136
01137
01138 if (npdu->control & BACNET_CTRL_MSGTYPE_MASK) {
01139 PRINT ("\n\tMSG TYPE: %d\n", data[0]);
01140 pr->msg_type = data[0];
01141 data = &(data[1]);
01142 }
01143
01144 return (EXIT_SUCCESS);
01145 }
01146