summaryrefslogtreecommitdiff
path: root/staging/mops.h
blob: cf19f09877c9677bf002927e0f2e1de630c9e037 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
/*
 * Mausezahn - A fast versatile traffic generator
 * Copyright (C) 2008-2010 Herbert Haas
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License version 2 as published by the 
 * Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with 
 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
 * 
*/


#ifndef __MOPS__
#define __MOPS__


#define MOPS_VERSION "0.3"
#define MOPS_CODENAME "Cyanistes caeruleus (DE+150)"
#define AUTOMOPS_ENABLED    0             // Automops subsystem (currently in development)
#define MAX_MOPS_FRAME_SIZE 8192          // total max frame size (=all headers plus payload)
#define MIN_MOPS_FRAME_SIZE 15            // total min frame size 
#define MOPS_SIZE_MARGIN    50            // User limit: MAX_MOPS_FRAME_SIZE - MOPS_SIZE_MARGIN
#define MAX_MOPS_MSG_SIZE 7500            // payload limit
#define MAX_MOPS_MSG_CHUNK_SIZE 1000      // Chunks size when read data from a file for the payload
#define MAX_MOPS_COUNTERS_PER_PACKET 10   // number of user-defined counters per packet
#define MAX_MOPS_PACKET_NAME_LEN 32       // Each packet must have an unique name
#define MAX_MOPS_DESCRIPTION_LEN 80       // Max length of packet description string
#define MAX_MOPS_DOT1Q_TAGS 64            // Max number of 802.1Q tags within a frame (too many, practically ;-))
#define MAX_MOPS_MPLS_TAGS 64             // Max number of MPLS tags within a frame (again too many, practically)
#define XN_MAX_STACK  7                   // max nesting depth

#define AUTOMOPS_MAX_FILE_SIZE  200000    // Max file size in bytes for AMP protocol definitions
#define AUTOMOPS_MAX_NAME_LEN       32    // used for all names (valname, field name, protocol name)
#define AUTOMOPS_MAX_SHORTDESC_LEN  64

#define XML_MAX_TAG_LEN             16   
#define XML_STRLEN                  64   // required length of user string to hold tag
                                         // but also alternatively an error message


#define MAX_LLDP_OPT_TLVS          500   // How many bytes are reserved for optional TLVs within an LLDP message?

//#define MAX_MOPS_PACKETS 1000             // number of packet slots *** DEPRECATED ***
#define MAX_CLI_LINE_BYTES 32             // How many bytes 'mops_print_frame' should print before line break

// Basic layers; see mops_clear_layers()
// Also used by automops (see layers_on, layers_off)
#define MOPS_ALL       127    
#define MOPS_ETH         1
#define MOPS_SNAP        2    // either LLC, LLC+SNAP
#define MOPS_dot1Q       4
#define MOPS_MPLS        8
#define MOPS_IP         16
#define MOPS_UDP        32
#define MOPS_TCP        64

// The following definitions are needed as values for (int) p_desc_type
// which identifies the exact type of (void *) p_desc.
#define MOPS_NO_PDESC 100
#define MOPS_ARP      101
#define MOPS_BPDU     102
#define MOPS_CDP      103
#define MOPS_DNS      104
#define MOPS_ICMP     105
#define MOPS_LLDP     106
#define MOPS_RTP      107
#define MOPS_SYSLOG   108
#define MOPS_IGMP     109

// packet states (variable 'state')
// NOTE: every state >2 (i. e. 3, 4, ...) is an active state, i. e. packet should 
//       be blocked from configurations etc.
#define MOPS_STATE_NULL   0   // transition state, only initially
#define MOPS_STATE_INIT   1   
#define MOPS_STATE_CONFIG 2   // normal state (when configured)
#define MOPS_STATE_ACTIVE 3   // has associated sending thread
#define MOPS_STATE_SEQACT 4   // packet is member of an active sequence

// Return values of mops_pdesc utility functions (see mops_ext.c)
#define MOPS_PDESC_SUCCESS      0   // Value assigned properly | string present
#define MOPS_PDESC_FAILURE      1   // Unspecified problem | string not present
#define MOPS_PDESC_LOW          2   // Value smaller than lower bound - but will set
#define MOPS_PDESC_HIGH         3   // Value larger than upper bound  - but will set
#define MOPS_PDESC_OVERFLOW     4   // Value exceeded possible range
#define MOPS_PDESC_NO_MAC       5   // Invalid MAC address
#define MOPS_PDESC_NO_IP        6   // Invalid IP address

// These definitions are (should be) only used in mops_ext.c
#define MOPS_EXT_ARP    struct mops_ext_arp *
#define MOPS_EXT_BPDU   struct mops_ext_bpdu *
#define MOPS_EXT_CDP    struct mops_ext_cdp *
#define MOPS_EXT_DNS    struct mops_ext_dns *
#define MOPS_EXT_ICMP   struct mops_ext_icmp *
#define MOPS_EXT_LLDP   struct mops_ext_lldp *
#define MOPS_EXT_RTP    struct mops_ext_rtp *
#define MOPS_EXT_SYSLOG struct mops_ext_syslog *
#define MOPS_EXT_IGMP   struct mops_ext_igmp *

// Very specific definitions here:
#define MOPS_RTP_EXT_MZID  0xcaca // first 16 bit of the Mausezahn RTP extension header
#define DSP_SOURCE         100    // any number >0 indicating /dev/dsp to be used as RTP payload
#define MOPS_RTP_MAX_PAYLOAD_SIZE 200

#include <pthread.h>


// These are initialized with the definitions MIN_MOPS_FRAME_SIZE and 
// MAX_MOPS_FRAME_SIZE above but can be overridden by the user (without
// extending these limits)
extern unsigned int min_frame_s;
extern unsigned int max_frame_s;

struct mops_counter
{
   int         use;     // 1 = counter active
   int         offset;  // points to counter location in *msg*
   int         random;  // 1=random, 0=use start/stop/step
   u_int32_t   start;   // HOST BYTE ORDER
   u_int32_t   stop;    // HOST BYTE ORDER
   u_int32_t   step;    // HOST BYTE ORDER
   u_int32_t   cur;     // current value (HOST BYTE ORDER)
   int         bytes;   // number of bytes used (1|2|4) - selects hton2 or hton4
                        // and enables proper wraparounds (mod 256, mod 65536, ...)
};


enum amperr {
	ampSuccess, 
	ampInvalidIndex, 
        ampInvalidName,
	ampDuplicateName,
	ampDescTooLong, 
	ampInvalidType,
	ampInvalidLayer,
	ampTCPandUDP,
	ampUnknownKeyword, 
	ampSingleWordRequired,
	ampRangeError,
	ampPayloadLen,
	ampPayloadType,
	ampUnknownTag
};

enum fieldtypes {
	Byte8, Byte16, Byte32, Flag_in_Byte, MultiBytes, MultiBytesHex,
	TLV // TODO: different/standard TLV formats (Cisco CDP, LLCP, ...)
};
	

struct fields {
	struct fields *next;
	char name[AUTOMOPS_MAX_NAME_LEN+1]; 	// Official name of field -- CASE INSENSITIVE
	char shortdesc[AUTOMOPS_MAX_SHORTDESC_LEN+1];   // One-line description
	char * longdesc;                                // Long (multiline) description (helptext)
	enum fieldtypes type;    // Field type corresponds to length
	int  constant;           // 1: only default value allowed, not changeable

	int i;     // unique internal field entry index (strongly monotonic increasing!)
	           // Note: first entry starts with 0.
	
	int index; // protocol field index; Note: First field has index 1.
	           // successive fields have same index in two cases:
	           //      1) several flags within same byte
	           //      2) several different valname/val pairs for same field index. In this
	           //         case the successive field-entries must only contain the valname
	           //         and a corresponding value.

	// may contain a reserved value *name*, usually used with multiple
	// successive fields with same field index N.
	char valname[AUTOMOPS_MAX_NAME_LEN+1];

	u_int32_t
		tlv_type, 
		tlv_len,
		val,      // default initial value
		min,      // range min value
		max;      // range max value

	int leftshift;    // when type=Flag_in_Byte
	
	u_int8_t *str;    // default initial characters or hex values (when type=MultiByte or TLV)
	int str_s;        // length of str
};


// Each automops object identifies another dynamically specified protocol.
// 
// Usage and structure:
// 
//  1) Doubly linked list to store new (dynamically defined) protocols.
//     Protocol definitions are typically loaded from a file and converted
//     to an automops entry via parse_protocol() defined in parse_xml.c
//  
//  2) When the user chooses one of these protocols to be used for a mops
//     then best is to copy the whole automops to the current mops; this
//     way the protocol's field values can be easily modified and 
//     automops_update() can be directly applied to that automops entity.
//     
//  If you cannot understand anything you are maybe already mausezahn'ed  ;-)
//     
struct automops {
	struct automops *next;
	struct automops *prev;
		
	char    name[AUTOMOPS_MAX_NAME_LEN+1];  // Protocol name
	char    desc[AUTOMOPS_MAX_SHORTDESC_LEN+1]; // One-line description               

	// Specify required and allowed layers using the definitions above
	// for example MOPS_ETH, MOPS_SNAP, MOPS_dot1Q, MOPS_MPLS, 
	//             MOPS_IP, MOPS_UDP, and MOPS_TCP
	int 
		layers_on,  // which layers are REQUIRED
		layers_off; // which layers MUST be DISABLED because of conflicts
	                    // Not mentioned layers are arbitrary (e. g. MOPS_dot1Q)
	// Protocol-specific addresses
	//    Usually only destination address/port is specific but there are some
	//    exceptions (e. g. DHCP uses well known sp/dp pair). 
        //    Value zero means ignore; otherwise copy to mops.
	u_int16_t etype;    // EtherType
	u_int8_t  proto;    // IP protocol number
        u_int8_t  sa[6], da[6];   // source/destination MAC address
        u_int32_t SA, DA;   // source/destination IPv4 address
	int     sp, dp;     // Well-known port numbers


	int     payload_type;     // 0=none, 1=ascii, 2=hex, 3=any
	char    *payload;         // default payload data (if above is true) 
	int     payload_s;
	
	struct fields *field; // points to single linked list describing each field
	                      // or NULL 
	
	/// ---- internal data -----
	int defined_externally; // 0=built-in, 1=file, -1=undefined		   
	int used; // number of mopses using this automops;
	          // = -1   when allocated 
	          // =  0   when got valid data
		  // = >0   when used by some mopses
};


extern struct automops * amp_head;


struct mops
{
   struct mops *next;
   struct mops *prev;
   
   // *** The Header ***
   // Management issues for TX
   int  state;                                      // see above
   int  id;                                         // UNIQUE Identifier (NOTE: MUST ALLOW -1)
   int  mz_system;                                  // identifies user and system packets (such as ARP)
   int  verbose;                                    // Be more or less verbose when processing that MOPS
   char packet_name[MAX_MOPS_PACKET_NAME_LEN];      // Each packet must have unique name
   char description[MAX_MOPS_DESCRIPTION_LEN];      // An optional short packet description

   pthread_t        mops_thread;                    // associated transmission thread
   pthread_t        interval_thread;
	
   pthread_mutex_t  mops_mutex;                     // mutex to savely access mops data
   
   char device[16];           // every packet could be sent through a different device
                              // NOTE that we do NOT store the index of device_list[] because after
			      // a re-discovery of the network interfaces the same index could map
			      // to a different physical network device. Instead the device's name
			      // does not change (however, might be not available, but then we report
			      // an error message and the user can assign another interface)
			      // 
			      // See function mops_get_device_index()
			      
   unsigned long count;       // Desired number of packets to be sent. 0 means infinite.
   unsigned long cntx;        // This value actually counts sent packets. 
                              // NOTE: Count _down_ for finite count, count _up_ for infinite count.

   struct timespec ndelay;    // Inter-packet delay; contains two members: 
	                      // tv_sec and tv_nsec (0 to 999999999)

   struct timespec interval;  // An optional global interval
   int             interval_used;  // 0=none, 1=configured, 2=active (i. e. interval_thread is valid)
   
   struct timespec delay_sigma;  // Standard deviation

   int           delay_pd;    // Which propability distribution (density)
                              //      MOPS_DELAY_GAUSS
                              //      MOPS_DELAY_EXP will result in a Poisson process with lambda=delay
			     
	
   int  auto_delivery_off;    // 0 means, the destination MAC address will be chosen automatically (for IP packets)
	                      // depending on the IP destination address ('direct or indirect delivery', i. e. based
			      // on ARP). 
			      // 
			      // 1 means, the user-provided destination MAC address will be used.
	
   // ******************
   
   // Data section
   
   int 
     use_ETHER,     // if unset (=0) then complete raw frame given in frame[]
     use_SNAP,      // NOTE: use_SNAP=1 may indicate either 802.3+LLC alone or 802.3+LLC+SNAP
     use_dot1Q,
     use_MPLS,
     use_IP,
     use_UDP,
     use_TCP;

   int                        // pointers to important positions
     begin_IP,                // marks byte position of IP header within frame
     begin_UDP,               // marks byte position of UDP header within frame
     begin_TCP,               // marks byte position of TCP header within frame
     begin_MSG;               // marks byte position of first message byte (=payload) within frame
   
   int  // **** get payload (message) from a file ****
     MSG_use_RAW_FILE,            // 1 means update function should copy next chunk from file
     MSG_use_HEX_FILE,            // same but assumes file content such as "aa:bb:cc:f3:1e:..."
     MSG_use_ASC_FILE;            // same but interpretes file content as ASCII characters
        // NOTE: if one of these are set to 1 then a filepointer is open !!!
   
   // A protocol descriptor (p_desc) is only used for some statically 
   // defined protocols. Originally intended for more complicated protocols
   // such as DNS.
   void * p_desc;       // optionally points to protocol descriptor (e. g. for DNS, CDP, etc)
   int    p_desc_type;  // identifies the exact type of p_desc
	
	
	
   // AutoMOPS provides a dynamic method to define new protocols. Here we need a pointer
   // to the protocol definition for convenience and the complete protocol header field
   // which is created by automops_update()
   // 
   // Note: The used 'amp' should be memcpy'd for this particular mops
   //       because then we can store current PDU values here and the 
   //       user can modify it later arbitrarily.
   // 
   //       Use  automops_clone_automops()  in automops.c for this.
   // 
   struct automops         *amp;  // points to protocol definition
   u_int8_t            *amp_pdu;  // contains the complete PDU as bytestring
   int                amp_pdu_s;
	
	
   // Resulting frame:
   u_int8_t   frame[MAX_MOPS_FRAME_SIZE];  // will hold the complete frame
   u_int32_t  frame_s;                     // indicates the total frame size
   
   
   // Ethernet parameters:
   u_int8_t  eth_dst[6];
   u_int8_t  eth_src[6];
   int       eth_src_israndom; // if set to 1 then the source address is to be randomized
   u_int16_t eth_type;
   u_int16_t eth_type_backup;  // if original type must be restored (e. g. when removing MPLS labels)
   
   // 802.3 parameters: LLC/SNAP
   u_int16_t eth_len;
   u_int8_t  eth_snap[16]; // AA-AA-03-<OUI>-<TYPE>
   int       eth_snap_s;   // usually 8 bytes

      
   // 802.1Q VLAN Tag   !!! NOTE: outer tag has lower index number (same byte-order as in frame[]) !!!
   u_int8_t  dot1Q[MAX_MOPS_DOT1Q_TAGS*4]; // All successive 802.1Q/P headers, 4 bytes per header: 0x8100, pri, cfi, id
   int       dot1Q_s;       // how many bytes from above are really used
   int       dot1Q_isrange; // if 1, only the outer tag loops through the range.
   int       dot1Q_start;
   int       dot1Q_stop;
		
	
   // MPLS label stack
   u_int8_t mpls[MAX_MOPS_MPLS_TAGS*4];   // All successive labels
   int      mpls_s;       // how many bytes from above are really used
   int      mpls_isrange; // if 1, only the outer tag loops through the range.
   int      mpls_start;  
   int      mpls_stop;
	
   // IP parameters -- NOTE: Everything here is in HOST BYTE ORDER !!!

   u_int32_t ip_src;          // By default interface address
   u_int32_t ip_src_start;    // start of range (HOST byte order => easy to count)
   u_int32_t ip_src_stop;     // stop of range  (HOST byte order => easy to count)
   int       ip_src_isrange;  // if set to 1 then the start/stop values above are valid.
   int       ip_src_israndom; // if set to 1 then the source address is to be randomized
   u_int32_t ip_dst;          // (HOST byte order)
   u_int32_t ip_dst_start;    // start of range (NOT network byte order => easy to count)
   u_int32_t ip_dst_stop;     // stop of range  (NOT network byte order => easy to count)
   int       ip_dst_isrange;  // if set to 1 then the start/stop values above are valid.
   u_int16_t 
     ip_len,
     ip_id,
     ip_frag_offset,          // 13 bit Offset: allowed values: 0..8191
     ip_sum;                  // TODO: provide variable 'ip_sum_false' to create false checksum for various tests
   int       ip_IHL_false;    // Default=0, set to 1 if user configured own (typically false) header length
   int       ip_len_false;    // Default=0, set to 1 if user configured own (typically false) total length
   int       ip_sum_false;    // Default=0, set to 1 if user configured own (typcially false) checksum
   u_int8_t 
     ip_version,
     ip_IHL,                  // header length (4 bits = 0..15)
     ip_tos,
     ip_flags_RS,             // 0|1 ... Reserved flag "must be zero"
     ip_flags_DF,             // 0|1 ... Don't Fragment 
     ip_flags_MF,             // 0|1 ... More Fragments
     ip_fragsize,             // if >0 it activates auto-fragmentation
     ip_frag_overlap,         // if >0 then all fragments overlap. Must be multiple of 8 but smaller than fragsize.
     ip_ttl,
     ip_proto;
   u_int8_t 
     ip_option[1024];         // Any IP Option used?
   int ip_option_used;        // >0 if yes. The exact number also indicates which option(s) used - see mops_ip.c
   u_int32_t 
     ip_option_s;


   // General L4 parameters:
   u_int16_t 
     sp, dp, 
     sp_start, sp_stop,
     dp_start, dp_stop;
   int 
     sp_isrand,                // if set to 1 then use random port number for each sent packet
     dp_isrand,                // if set to 1 then use random port number for each sent packet
     sp_isrange,               // if set to 1 then start/stop values above are valid
     dp_isrange;               // if set to 1 then start/stop values above are valid
   
   // UDP parameters
   u_int16_t 
     udp_len,                  // includes header size (8 bytes)
     udp_sum;
   int   udp_sum_false;        // Default=0, set to 1 if user configured own (typcially false) checksum
   int   udp_len_false;        // Default=0, set to 1 if user configured own (typcially false) length
   
   // TCP parameters (RFC 793)
   // 
   //     0                   1                   2                   3   
   //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   //    |          Source Port          |       Destination Port        |
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   //    |                        Sequence Number                        |
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   //    |                    Acknowledgment Number                      |
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   //    |  Data |           |U|A|P|R|S|F|                               |
   //    | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   //    |       |           |G|K|H|T|N|N|                               |
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   //    |           Checksum            |         Urgent Pointer        |
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   //    |                    Options                    |    Padding    |
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   //    |                             data                              |
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   // 
   u_int32_t 
     tcp_seq, 
     tcp_seq_start,
     tcp_seq_stop,             
     tcp_seq_delta,            // Also used instead of an 'isrange' variable
     tcp_ack,
     tcp_ack_start,
     tcp_ack_stop,
     tcp_ack_delta;            // Also used instead of an 'isrange' variable
   u_int8_t 
     tcp_offset,               // Header length in multiples of 32 bit (4 bit value, 0..15)
     tcp_res,                  // reserved (4 bits)
     tcp_ctrl_CWR,             // 0|1 - Congestion Window Reduced [RFC-3168]
     tcp_ctrl_ECE,             // 0|1 - ECN-Echo [RFC-3168]
     tcp_ctrl_URG,             // 0|1 
     tcp_ctrl_ACK,             // 0|1 
     tcp_ctrl_PSH,             // 0|1 
     tcp_ctrl_RST,             // 0|1 
     tcp_ctrl_SYN,             // 0|1 
     tcp_ctrl_FIN;             // 0|1 
   u_int16_t 
     tcp_win, 
     tcp_sum, 
     tcp_urg,
     tcp_len;                  // Only needed for the checksum calculation and is not transmitted (host order!)
     
   int
     tcp_sum_false,            // Default=0, set to 1 if user configured own (typcially false) checksum
     tcp_offset_false;         // Default=0, set to 1 if user configured own (typcially false) offset
   u_int8_t
     tcp_option[1024];
   u_int32_t
     tcp_option_s;
   int tcp_option_used;        // >0 if yes. The exact number also indicates which option(s) used - see mops_tcp.c
   
   
   // Message:
   u_int8_t   msg[MAX_MOPS_MSG_SIZE];
   u_int32_t  msg_s;  
   FILE *fp;  // points to file if MSG_use_RAW_FILE or MSG_use_HEX_FILE or MSG_use_ASC_FILE is set to 1
   u_int32_t  chunk_s;  // max chunk size to be copied from file
   
   
   // User-defined counters:
   struct mops_counter counter[MAX_MOPS_COUNTERS_PER_PACKET];
   int used_counters;   // number of currently defined counters
   
};



struct mops_ext_arp 
{
   u_int16_t  hw_type;
   u_int16_t  pr_type;
   u_int8_t   hw_size;
   u_int8_t   pr_size;
   u_int16_t  opcode;
   u_int8_t   sender_mac[6];
   u_int8_t   sender_ip[4];
   u_int8_t   target_mac[6];
   u_int8_t   target_ip[4];
   u_int16_t  trailer;
};



struct mops_ext_bpdu // TODO
{
   u_int16_t  id;       
   u_int8_t   version;       // 0=802.1D, 2=RSTP(802.1w)
   u_int8_t   bpdu_type;     // 0=conf, 1=topology change (actually in big endian!), 2=RSTP/MSTP
   u_int8_t   flags;            // X... .... = TCN ACK
                                // .X.. .... = Agreement
                                // ..X. .... = Forwarding
			        // ...X .... = Learning
			        // .... XX.. = Port Role (e. g. 11=Desgn)
			        // .... ..X. = Proposal
			        // .... ...X = TCN
   u_int8_t   root_id[8];    // Root BID 
   u_int32_t  root_pc;       // Root Path Cost
   u_int8_t   bridge_id[8];  // Own BID
   u_int16_t  port_id;       // Port Identifier
   u_int16_t  message_age;   // All timers are multiples of 1/256 sec. Thus times range from 0 to 256 seconds.
   u_int16_t  max_age; 
   u_int16_t  hello_time;
   u_int16_t  f_delay;
   u_int8_t   trailer[8];    // either all-zero or 34:00:02:VLAN(16bit):00:00 when PVST+

   int rstp; // 1 = RSTP
   int pvst; // 1=PVST+ , 0 = 802.1D
   int mstp; // 1 = Multiple Instance STP
   
};

struct mops_ext_lldp {
	int non_conform; // if 1 then the order of TLVs is arbitrary
	int chassis_id_subtype;
	int chassis_id_len;
	u_int8_t *chassis_id;
	int port_id_subtype;
	int port_id_len;
	u_int8_t *port_id;
	int TTL;
	int optional_tlvs_s;
	u_int8_t *optional_tlvs;
	
};

enum igmp_type {IGMP_GENERAL_QUERY, 
		IGMP_GSPEC_QUERY, 
		IGMP_V2_REPORT, 
		IGMP_V1_REPORT, 
		IGMP_LEAVE};

struct igmp_sa_struct { // For single linked list to hold unicast addresses for IGMPv3 query
	u_int32_t sa;
	struct igmp_sa_struct *next;
};

struct igmp_aux_struct { // For single linked list to hold auxilary data for IGMPv3 report
	u_int32_t aux_data;
	struct igmp_aux_struct *next;
};


struct igmp_group_struct { // For single linked list to hold IGMPv3 group records
	u_int8_t       record_type;
	u_int8_t       aux_data_len;
	u_int16_t      nr_sources;
	u_int32_t      mcast_addr;
	struct igmp_sa_struct  *sa_list;
	struct igmp_aux_struct *aux_list;
	struct igmp_group_struct *next;
};



struct mops_ext_igmp  {
	int        version;       // internal, not in header
	u_int8_t   type;
	u_int8_t   max_resp_code; // equally: 'max response time' for IGMPv2
	u_int16_t  sum;
	int        sum_false;     // if '1' then sum contains user-provided checksum; if '0' then autocompute!
	u_int32_t  group_addr;
	u_int8_t 
		resv4,          // resv4 + S + QRV => one byte in IGMPv3 query
		S,              // S = Suppress Router-Side Processing
		QRV;            // QRV = Querier's Robustness Variable
	u_int8_t   resv8;       // needed in IGMPv3 response AND IGMPv1 query+response
	u_int16_t  resv16;      // needed in IGMPv3 response       
	u_int8_t   QQIC;        // Querier's Query Interval Code
	u_int16_t  nr_entries;  // either number of sources (=query) or group records (=response)
	struct igmp_sa_struct *sa_list;
};


struct mops_ext_cdp // TODO
{
   u_int8_t   id;
   u_int16_t  hw_type;
};

struct mops_ext_dns // TODO: complete
{
   // Main 16-bit fields
   u_int16_t  id;
   u_int16_t  num_queries;
   u_int16_t  num_answers;
   u_int16_t  num_author;
   u_int16_t  num_add;
   u_int16_t  type;
   
   // Flags (1 bit, except where noted)
   u_int8_t   qr;
   u_int8_t   opcode;  // 4 bits
   u_int8_t   aa;
   u_int8_t   tc;
   u_int8_t   rd;
   u_int8_t   ra;
   u_int8_t   z;       // 3 bits
   u_int8_t   rcode;   // 4 bits
   
};


struct mops_ext_icmp // TODO
{
   u_int8_t   id;
   u_int16_t  hw_type;
};

struct mops_ext_rtp 
{
   // Vars to hold flag values:
   u_int8_t   v,
	      p,
	      x,  // only sets the flag; if you really want an extension header also set "x_type" (see below)
	      cc, // csrc_count visible in header (has no further meaning, thus support for "wrong" headers)
	      cc_real, // real csrc_count (only used internally to create CSRC list)
	      m,
	      pt; // selects inter-packet delay and payload_s;
	
   u_int16_t  sqnr;  // initial sqnr
   u_int32_t  tst;   // initial timestamp
   u_int32_t  ssrc;  // !!! also used to identify measurement streams !!!
   u_int32_t  csrc[16]; // NOTE: only up to 15 CSRC's are allowed according RFC 3550
	
   // additionally:
   int        tst_inc;        // The increment of the tst (depends on codec)
   u_int8_t   payload[MOPS_RTP_MAX_PAYLOAD_SIZE];   // 
   int        payload_s;      // is the same as tst_inc when codec is G.711 but different with other codecs!
   int        source;         // Optionally draw data from file or /dev/dsp or such [TODO]
   int        rtp_header_len; // will be set by mops_update_rtp()
   // one optional header extension:
   int        x_type; // IMPORTANT: which extension header to use: 0 = none, 42 = Mausezahn, 1 = Aero
   u_int8_t   extension[64]; // a user configurable extension header [CURRENTLY UNUSED]
};



struct mops_ext_syslog //TODO
{
   u_int16_t  hw_type;
   u_int16_t  pr_type;
};

   
/////////////////////////////////////////////////////////////////

extern struct mops *mp_head; // This global will point to the head of the mops list

/////////////////////////////////////////////////////////////////
// MOPS Prototypes:

void mops_hton2 (u_int16_t *host16, u_int8_t *net16);
void mops_hton4 (u_int32_t *host32, u_int8_t *net32);

int  mops_get_proto_info (struct mops *mp, char *layers, char *proto);

// Inserts value in 'flag' (up to 7 bits are useful) into the target
// with an optional left-shift. For example if flag contains a 4-bit value
// and should be placed within the target in bit positions 3-6 like:
// 
//   7  6  5  4  3  2  1  0   
// +--+--+--+--+--+--+--+--+
// |  |  FLAGS    |  |  |  |
// +--+--+--+--+--+--+--+--+
// 
// then simply call: 
// 
//    (void)  mops_flags ( &target, &flag, 3 );
// 
// Note:
//     1) shift=0 means no shift
//     2) Because of speed we do not check if the arguments are reasonable
//     
void mops_flags (u_int8_t *target, u_int8_t *flag, int shift);

u_int16_t mops_sum16 (u_int16_t len, u_int8_t buff[]);

struct mops * mops_init(void);
struct mops * mops_alloc_packet (struct mops *cur);
struct mops * mops_delete_packet (struct mops *cur);
int mops_reset_packet(struct mops *cur);
	
int    mops_dump_all (struct mops* list, char* str);
struct mops * mops_search_name (struct mops* list, char *key);
struct mops * mops_search_id (struct mops* list, u_int32_t key);

void   mops_delete_all (struct mops* list);
void   mops_cleanup   (struct mops* list);

// State functions
int mops_state (struct mops *mp);
int mops_is_active (struct mops *mp);
void mops_set_conf (struct mops *mp);
void mops_set_active (struct mops *mp);
void mops_set_seqact (struct mops *mp);
int mops_is_seqact (struct mops *mp);
int mops_is_any_active (struct mops *mp);

// For debugging purposes
int   mops_print_frame (struct mops *mp, char *str);

// sets UDP or TCP checksum within mp->frame
// TODO: copying the whole segment is ugly and slow;
//       make it more efficient and realize it in-place.
//         
int  mops_get_transport_sum  (struct mops *mp);

// returns new counter index for given packet
// or -1 if all counters used already
int mops_get_counter (struct mops *mp);

// This is the very basic MOPS update function. It simply updates the whole
// MOPS frame specified by pointer mp. If you only want to update specific
// details then please see the other related specialized functions which are
// faster.
int mops_update (struct mops *mp);

int mops_set_defaults (struct mops *mp);

// Get global device index for a given device name.
int mops_get_device_index(char *devname);

// Assign device-specific addresses to packet.
int mops_use_device(struct mops * clipkt, int i);

// Find and returns a new unique packet id
// If none can be found, returns -1.
int mops_get_new_pkt_id (struct mops *mp);

// Simply sets specified 'layer switches' in struct mops to zero
int mops_clear_layers (struct mops *mp, int l);

// Transmission functions
int mops_tx_simple (struct mops *mp);
void *mops_tx_thread_native (void *arg);
void *mops_interval_thread (void *arg);
void *mops_sequence_thread (void *arg);


int mops_destroy_thread (struct mops *mp);

// Utility functions for packet headers (aka *** METHODS *** for the object-oriented nerds)
int mops_dot1Q_remove (struct mops *mp, int k);
int mops_dot1Q_nocfi (struct mops *mp, int k);
int mops_dot1Q_cfi (struct mops *mp, int k);
int mops_dot1Q (struct mops *mp, int i, int m, u_int16_t v, u_int16_t c);

int mops_mpls_remove (struct mops *mp, int j);
int mops_mpls_bos (struct mops *mp, int k);
int mops_mpls_nobos (struct mops *mp, int k);
int mops_mpls(struct mops *mp, int i, int m, u_int32_t Label, u_int8_t Exp, u_int8_t TTL);

int mops_ip_get_dst_mac(struct device_struct *dev, u_int8_t *ip, u_int8_t *mac);
int mops_ip_dscp(struct mops *mp, char *argv);
int mops_ip_tos (struct mops* mp, int ipp, int tos, int mbz);
int mops_ip_option_ra (struct mops* mp, int value);
int mops_ip_option_remove_all (struct mops* mp);

u_int32_t mops_tcp_complexity_sqnr (struct mops * mp);
u_int32_t mops_tcp_complexity_acknr (struct mops * mp);

// Prints current flag settings in the provided string 'str'.
int mops_tcp_flags2str (struct mops* mp, char *str);

int mops_tcp_add_option (struct mops* mp, 
			 int mss, 
			 int sack,
			 int scale, 
			 u_int32_t tsval, 
			 u_int32_t tsecr);


//////////////////////////////////////////////////////////////////////////////
//
// ****** The following are important to easily create new packet types ******
//
//////////////////////////////////////////////////////////////////////////////

// Adds single byte to msg
int mops_msg_add_byte (struct mops *mp, u_int8_t data);

// Adds bit field in *previous* msg-byte using optional left-shift
int mops_msg_add_field (struct mops *mp, u_int8_t data, int shift);

// Adds two bytes in network byte order to msg
int mops_msg_add_2bytes (struct mops *mp, u_int16_t data);

// Adds four bytes in network byte order to msg
int mops_msg_add_4bytes (struct mops *mp, u_int32_t data);

// Adds string of bytes with lenght len 
int mops_msg_add_string (struct mops *mp, u_int8_t *str, int len);

// Add counter to message
int mops_msg_add_counter (struct mops *mp,
			  int         random,  // 1=random, 0=use start/stop/step
			  u_int32_t   start,   // HOST BYTE ORDER
			  u_int32_t   stop,    // HOST BYTE ORDER
			  u_int32_t   step,    // HOST BYTE ORDER
			  int         bytes   // number of bytes used (1|2|4) - selects hton2 or hton4
			  );

// Returns 0 if identical, 1 if different
int compare_ip (u_int8_t *ip1, u_int8_t *ip2);

// Returns 0 if identical, 1 if different
int compare_mac (u_int8_t *mac1, u_int8_t *mac2);

// Converts a 'struct timespec' value into a human readable string
int timespec2str(struct timespec *t, char *str);

// -------------------------------------------------------------------------------

// Add protocol descriptor of type ptype
// 
// Smart behaviour: If a p_desc has been already assigned, this function 
// clears and frees everything before assigning another p_desc structure.
// 
int mops_ext_add_pdesc (struct mops *mp, int ptype);

// Create msg based on p_desc data.
// After that call mops_update and the frame is complete.
int mops_ext_update (struct mops *mp);

// Delete any protocol descriptor
int mops_ext_del_pdesc (struct mops *mp);

// Initialization functions for p_desc
int mops_init_pdesc_arp(struct mops *mp);
int mops_init_pdesc_bpdu(struct mops *mp);
int mops_init_pdesc_cdp(struct mops *mp);
int mops_init_pdesc_dns(struct mops *mp);
int mops_init_pdesc_icmp(struct mops *mp);
int mops_init_pdesc_igmp(struct mops *mp);
int mops_init_pdesc_lldp(struct mops *mp);
int mops_init_pdesc_syslog(struct mops *mp);
int mops_init_pdesc_rtp(struct mops *mp);

int mops_create_igmpv2 (struct mops *mp,
			int override,   // normally zero, but if '1' the user want to override defaults
			int igmp_type, // IGMP_GENERAL_QUERY, IGMP_GSPEC_QUERY, IGMP_V2_REPORT, IGMP_V1_REPORT, IGMP_LEAVE
			int  mrt, // max response time
			int  sum, //-1 means auto-compute, other values means 'use this user-defined value'
			u_int32_t group_addr);


// Update functions for p_desc => msg
int mops_update_arp(struct mops * mp);
int mops_update_bpdu(struct mops * mp);
int mops_update_igmp (struct mops * mp);
int mops_update_lldp (struct mops * mp);
int mops_update_rtp (struct mops * mp);
int mops_update_rtp_dynamics (struct mops * mp);

// Utility functions for p_desc
int mops_pdesc_mstrings (char *dst, char* argv[], int argc, int max);
int mops_pdesc_1byte (u_int8_t *dst, char* usr, int spec, int min, int max);
int mops_pdesc_2byte (u_int16_t *dst, char* usr, int spec, int min, int max);
int mops_pdesc_4byte (u_int32_t *dst, char* usr, int spec, unsigned long int min, unsigned long int max);
int mops_pdesc_mac (u_int8_t *dst, char* usr);
int mops_pdesc_ip (u_int8_t *dst, char* usr);

// Other p_desc related functions
int mops_create_bpdu_bid(struct mops * mp, int pri, int esi, char *mac, int bid_or_rid);
int mops_create_bpdu_trailer (struct mops * mp, u_int16_t vlan);
int mops_lldp_tlv (u_int8_t *tlv, int type, int len, u_int8_t *value);
int mops_lldp_tlv_chassis (u_int8_t *tlv, int subtype, int len, u_int8_t *cid);
int mops_lldp_tlv_port (u_int8_t *tlv, int subtype, int len, u_int8_t *pid);
int mops_lldp_tlv_TTL (u_int8_t *tlv, int ttl);
int mops_lldp_tlv_end (u_int8_t *tlv);
int mops_lldp_opt_tlv_bad (struct mops *mp, int type, int badlen, int len, u_int8_t *value);
int mops_lldp_opt_tlv_org (struct mops *mp, int oui, int subtype, int len, u_int8_t *inf);
int mops_lldp_opt_tlv_chassis (struct mops *mp, int subtype, int len, u_int8_t *cid);
int mops_lldp_opt_tlv_port (struct mops *mp, int subtype, int len, u_int8_t *pid);
int mops_lldp_opt_tlv_TTL (struct mops *mp, int ttl);
int mops_lldp_opt_tlv_vlan (struct mops *mp, int vlan);
int mops_lldp_opt_tlv (struct mops *mp, int type, int len, u_int8_t *value);
int mops_lldp_opt_tlv_end (struct mops *mp) ;


/////////////////////////// Services /////////////////////////////

// ARP Service: Resolves MAC address of given IP address and interface
int service_arp(char *dev, u_int8_t *ip, u_int8_t *mac);

int mops_rx_arp(void);
void *rx_arp (void *arg);
void got_arp_packet (u_char *args, const struct pcap_pkthdr *header, const u_char *packet);


//////////////////// directmops prototypes: ///////////////////////////
int mops_direct(char* dev, int mops_type, char* argstring);


//////////////////// automops prototypes: //////////////////////////////////


struct automops * automops_init(void);
struct automops * automops_alloc_protocol();
struct automops * automops_delete_protocol();
struct automops * automops_search_protocol();
int               automops_dump_all (struct automops* list);
void              automops_set_defaults(struct automops * cur);
struct fields *   automops_add_field (struct automops *amp);
void              automops_field_set_defaults(struct fields *f);
int               automops_delete_fields (struct automops *amp);
int               mops_str2layers(char *d);
int               amp_add_pentry (struct automops *amp, int xntag, char *d);
int               amp_add_fentry (struct automops *amp, struct fields *f, int xntag, char *d);
int               amp_checkindex(struct automops *amp, int i);
int               amp_str2type(char *d);
int               amp_type2str(int t, char *s);
struct fields *   amp_getfield_byname(struct automops *amp, char *d);
struct automops * amp_getamp_byname(struct automops *head, char *d);
// Creates an independent automops element for mops
// (it will be not part of any linked list so, next=prev=NULL)
struct automops * automops_clone_automops(struct automops * amp);
int               amperr2str (int e, char *s);

// Create automops PDU within *mp based on data in *amp
// 
int automops_update (struct mops *mp, struct automops *amp);
void automops_cleanup (struct automops *list);

char * mapfile (char *fn);

//////////////////////////  XML support //////////////////////////////
//
//


// Simple stack needed to check proper XML nesting.
// The corresponding methods are defined at the bottom.
struct xnstack {
	int data[XN_MAX_STACK];
	int cursize;
};

enum xml_tags { // mention all allowed tags here!
        	xml_protocol,
		xml_field,
		xml_name,
		xml_desc,
		xml_requires,
		xml_conflicts,
		xml_payloadtype,
		xml_payload,
		xml_payloadhex,
		xml_index,
		xml_longdesc,
		xml_type,
		xml_constant,
		xml_value,
		xml_valname,
		xml_min,
		xml_max,
		xml_tlvt,
		xml_tlvl,
		xml_lshift
};


int xml_check_parent(int t, int p);
int xml_tag2int (char *t);

int parse_protocol (char *p);
int xml_getnext_tag (char *p, char *t);
int xml_canonic (char *p);
int xml_get_data (char *p, char *t);
int xml_readin (struct automops *amp, char *p);

void xnstack_init(struct xnstack *s);
int xnstack_get_top(struct xnstack *s);
int xnstack_push(struct xnstack *s, int d);
int xnstack_pop(struct xnstack *s);
int xnstack_size(struct xnstack *s);

#endif