2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
23 // Creates first element, aka "head" element
24 // This element can also be used! See automops_alloc_protocol!
26 struct automops
* automops_init()
28 // Create initial automops element:
29 struct automops
*new_automops
= (struct automops
*) malloc(sizeof(struct automops
));
30 new_automops
->next
= new_automops
;
31 new_automops
->prev
= new_automops
;
32 automops_set_defaults (new_automops
);
33 new_automops
->used
= -1; // freshly created, no valid data in it
39 // (Re-)sets anything within the specified automops element
40 void automops_set_defaults(struct automops
* cur
)
44 mz_strncpy(cur
->name
, "user_proto", 16);
45 mz_strncpy(cur
->desc
, "undefined", 16);
53 cur
->da
[i
] = 0xff; // bcast (silly?)
55 cur
->SA
= cur
->DA
= 0;
56 cur
->sp
= cur
->dp
= 0;
58 cur
->payload_type
= 0; // both ascii or hex
61 cur
->defined_externally
= -1; // undefined
62 if (cur
->field
!= NULL
) automops_delete_fields (cur
);
67 // Returns pointer to new automops element:
68 // 1) either insert a new automops element in list
69 // 2) or returns same pointer again if current automops element is empty
70 // Note that new element N is always PREPENDED to cur:
71 // ... = N-2 = N-1 = N = cur = 1 = 2 = ...
72 // Therefore, cur should be typically a pointer to the head element
74 struct automops
* automops_alloc_protocol(struct automops
*cur
)
76 struct automops
*new_automops
;
78 if (cur
->used
== -1) // allows to use head element in list
80 new_automops
= cur
; // current automops was unused => no need to insert a new one!
82 else // create new automops element
84 new_automops
= (struct automops
*) malloc(sizeof(struct automops
));
85 if (new_automops
==NULL
)
87 fprintf(stderr
, "MZ alert: cannot create new automops entry - memory full?\n");
88 return NULL
; // memory full?
90 new_automops
->field
=NULL
; // don't remove this! See automops_set_defaults() to understand.
91 automops_set_defaults(new_automops
);
96 // append to doubly linked list
97 new_automops
->prev
= cur
->prev
;
98 new_automops
->next
= cur
;
99 cur
->prev
= new_automops
;
100 new_automops
->prev
->next
= new_automops
;
106 // Delete particular protocol (remove it from list or mops).
108 // If amp_head is deleted, makes previous element amp_head.
109 // Note that the global amp_head must exist but within MOPS this
110 // is always the case.
114 // - pointer to previous element in the list
115 // - NULL if current automops is used by some mops(es)
116 // (in this case, we may still need it, maybe the user wants
117 // to modify data or wants other information...?)
119 // - NULL if current element is a single element attached to a mops
121 struct automops
* automops_delete_protocol(struct automops
*cur
)
123 struct automops
*last
;
125 // Maybe the following is not really practical? /////
129 /////////////////////////////////////////////////////
131 // delete fields list:
132 automops_delete_fields (cur
);
134 if (cur
->payload_s
) free (cur
->payload
);
136 if ((cur
!=amp_head
) && (cur
->prev
==NULL
) && (cur
->next
==NULL
)) {
137 // this one is attached to a mops
138 if (cur
!=NULL
) free (cur
);
142 // part of linked list
144 cur
->next
->prev
= cur
->prev
;
145 cur
->prev
->next
= cur
->next
;
149 if (cur
!=NULL
) free (cur
);
156 // Search automops element for a given protocol name
158 // Returns pointer to that automops element
159 // or NULL if not found
161 struct automops
* automops_search_protocol(struct automops
*list
, char *name
)
163 struct automops
*head
= list
;
164 struct automops
*cur
= list
;
167 if ( (strncasecmp(name
, cur
->name
,
168 AUTOMOPS_MAX_NAME_LEN
) == 0)) {
169 return cur
; // FOUND!
172 } while (head
!= cur
);
174 return NULL
; // NOT FOUND!
179 // Runs through all automops entries and dumps some basic info
180 // Returns the number of used protocols
182 int automops_dump_all(struct automops
* list
)
184 struct automops
*head
= list
;
185 struct automops
*cur
= list
;
186 struct fields
*f
=NULL
;
187 int anzmops
=0, used
=0;
188 char str
[64], ft
[32];
191 char bits_on
[18], bits_off
[18];
196 fprintf(stderr
, "AUTOMOPS: Initial element\n");
197 if ((cur
->next
==cur
)&&(cur
->prev
==cur
))
198 fprintf(stderr
, " No other elements found.\n");
201 if (cur
->used
>0) used
++;
203 SA
=ntohl(cur
->SA
); x
= (uint8_t*) &SA
;
204 DA
=ntohl(cur
->DA
); y
= (uint8_t*) &DA
;
205 char2bits(cur
->layers_on
, bits_on
);
206 char2bits(cur
->layers_off
, bits_off
);
207 fprintf(stderr
, "Protocol %i: %s -- %s\n"
208 " Layercodes: X T U I M Q S E\n"
209 " requires %s (0x%02x)\n"
210 " conflicts %s (0x%02x)\n"
211 " L2: EtherType=%04x, sa=%02x:%02x:%02x:%02x:%02x:%02x, da=%02x:%02x:%02x:%02x:%02x:%02x\n"
213 anzmops
, cur
->name
, cur
->desc
,
214 bits_on
, cur
->layers_on
, bits_off
, cur
->layers_off
,
215 cur
->etype
, cur
->sa
[0], cur
->sa
[1], cur
->sa
[2], cur
->sa
[3], cur
->sa
[4], cur
->sa
[5],
216 cur
->da
[0], cur
->da
[1], cur
->da
[2], cur
->da
[3], cur
->da
[4], cur
->da
[5]);
217 if (cur
->layers_on
&MOPS_IP
) {
218 fprintf(stderr
, " IP: proto=%i, SA=%u.%u.%u.%u, DA=%u.%u.%u.%u\n",
219 cur
->proto
, *x
, *(x
+1), *(x
+2), *(x
+3), *y
, *(y
+1), *(y
+2), *(y
+3));
221 fprintf(stderr
, " IP: ---\n");
223 // Walk through field data:
226 j
++; // count number of fields
229 if (f
->longdesc
!=NULL
) {
230 mz_strncpy(str
, f
->longdesc
, 60);
231 if (strnlen(str
,60)>=59) i
=1;
234 mz_strncpy(str
, "-- no long description specified --", 60);
236 amp_type2str(f
->type
, ft
);
237 fprintf(stderr
, " %02i Field [%i] '%s' -- %s\n"
238 " Description: %s%s\n"
239 " Type: %s %s %s (%lu/%lu) {%lu..%lu..%lu} shift: %i; %i chars\n"
240 ,f
->i
, f
->index
, f
->name
, f
->shortdesc
,
241 str
, (i
) ? "..." : "",
242 ft
, (f
->constant
) ? "FIXED" : "",
243 (f
->valname
!=NULL
) ? f
->valname
: "(no value name)" ,
244 (long unsigned int) f
->tlv_type
,
245 (long unsigned int) f
->tlv_len
,
246 (long unsigned int) f
->min
,
247 (long unsigned int) f
->val
,
248 (long unsigned int) f
->max
,
249 f
->leftshift
, f
->str_s
);
253 if (verbose
==0) fprintf(stderr
, " %i fields defined.\n", j
);
254 //---------------------------------
256 } while (head
!= cur
);
263 // Creates an independent automops element for mops
264 // (it will be not part of any linked list so, next=prev=NULL)
266 // RETURN VALUE: - Pointer to the cloned automops
267 // - NULL upon failure
269 struct automops
* automops_clone_automops(struct automops
* amp
)
271 struct automops
*new_automops
;
272 struct fields
*f
, *g
, *h
=NULL
;
276 new_automops
= (struct automops
*) malloc(sizeof(struct automops
));
277 if (new_automops
==NULL
) {
278 fprintf(stderr
, "MZ alert: cannot create new automops element - memory full?\n");
279 return NULL
; // memory full?
282 // Copy the automops items
283 new_automops
->next
= NULL
;
284 new_automops
->prev
= NULL
;
286 strncpy(new_automops
->name
, amp
->name
, AUTOMOPS_MAX_NAME_LEN
);
287 strncpy(new_automops
->desc
, amp
->desc
, AUTOMOPS_MAX_SHORTDESC_LEN
);
288 new_automops
->layers_on
= amp
->layers_on
;
289 new_automops
->layers_off
= amp
->layers_off
;
290 new_automops
->etype
= amp
->etype
;
291 new_automops
->proto
= amp
->proto
;
292 for (i
=0; i
<6; i
++) {
293 new_automops
->da
[i
] = amp
->da
[i
]; // dst mac
294 new_automops
->sa
[i
] = amp
->sa
[i
]; // src mac
296 new_automops
->DA
= amp
->DA
; // dst IP
297 new_automops
->SA
= amp
->SA
; // src IP
298 new_automops
->dp
= amp
->dp
; // dst port
299 new_automops
->sp
= amp
->sp
; // src port
300 new_automops
->defined_externally
= amp
->defined_externally
;
301 new_automops
->payload_type
= amp
->payload_type
;
302 if (amp
->payload_s
) {
303 new_automops
->payload
= (char*) malloc(amp
->payload_s
);
304 if (new_automops
->payload
==NULL
) {
305 fprintf(stderr
, "MZ alert: cannot create new automops payload element - memory full?\n");
306 return NULL
; // memory full?
308 memcpy((void*) new_automops
->payload
, amp
->payload
, amp
->payload_s
);
311 new_automops
->used
= amp
->used
;
313 ////////////////////////////////////////////////////////////////////////////////////////////////
315 // Copy the fields list
317 new_automops
->field
= NULL
;
318 for (f
=amp
->field
; f
!=NULL
; f
=f
->next
) {
319 g
= (struct fields
*) malloc(sizeof(struct fields
));
321 fprintf(stderr
, "MZ alert: cannot create new field element - memory full?\n");
322 return NULL
; // memory full?
324 if (new_automops
->field
==NULL
) { // first element
325 new_automops
->field
= g
;
327 } else { // next elements
331 // copy all data. From here on 'h' is the new one, 'f' is the existing one
332 mz_strncpy(h
->name
, f
->name
, AUTOMOPS_MAX_NAME_LEN
);
333 mz_strncpy(h
->shortdesc
, f
->shortdesc
, AUTOMOPS_MAX_SHORTDESC_LEN
);
334 mz_strncpy(h
->valname
, f
->valname
, AUTOMOPS_MAX_NAME_LEN
);
335 if (f
->longdesc
!=NULL
) {
336 h
->longdesc
= (char*)
337 malloc(strnlen(f
->longdesc
, 1600)); // 80 chars x 20 lines should be enough
338 if (h
->longdesc
== NULL
) {
339 fprintf(stderr
, "MZ alert: cannot allocate memory!\n");
340 return NULL
; // memory full?
342 strncpy(h
->longdesc
, f
->longdesc
, 1600);
346 h
->str
= (u_int8_t
*) malloc(f
->str_s
);
347 if (h
->str
== NULL
) {
348 fprintf(stderr
, "MZ alert: cannot allocate memory!\n");
349 return NULL
; // memory full?
351 memcpy((void*) h
->str
, (void*) f
->str
, f
->str_s
);
353 h
->constant
= f
->constant
;
355 h
->tlv_type
= f
->tlv_type
;
356 h
->tlv_len
= f
->tlv_len
;
360 h
->leftshift
= f
->leftshift
;
367 // Add a new field object
368 struct fields
* automops_add_field (struct automops
*amp
)
370 struct fields
*f
, *f_prev
=NULL
, *g
;
373 // jump to the end of the fields list
381 g
= (struct fields
*) malloc(sizeof(struct fields
));
383 if (verbose
) fprintf(stderr
, "MZ alert: cannot create new field element - memory full?\n");
384 return NULL
; // memory full?
387 if (amp
->field
==NULL
) { // is is first element in amp
389 } else { // it is just another element in the fields list
392 g
->next
=NULL
; // 'pointing to NULL' identifies the last element
393 g
->i
=i
; // each field element has a unique internal number
394 g
->index
=0; // indicates 'empty' field
395 automops_field_set_defaults(g
);
400 // Typically only used by automops_add_field()
401 // Only call this function after creating a new field element
402 void automops_field_set_defaults(struct fields
*f
)
405 f
->shortdesc
[0]=0x00;
409 //NOTE: f->i MUST NOT be reset!
424 // Returns integer equivalent for a string of basic protocols.
425 // For example returns MOPS_ETH | MOPS_IP for d="eth ip".
426 // See the definitions in mops.h.
428 // NOTE: Does (and must) NOT verify whether items are conflicting
429 // such as "udp tcp". This task MUST be done by callee, otherwise
430 // this function's purpose would be not generic enough.
433 // The sum of basic protocols
434 // or -1 upon failure.
435 int mops_str2layers(char *d
)
440 // dissalow too long strings.
441 if (strlen(d
)>50) return -1; // TODO: replace 100 to a more reasonable value
445 if (strncasecmp("eth", d
, 10)==0) ret
|= MOPS_ETH
;
447 if (strncasecmp("snap", d
, 10)==0) ret
|= MOPS_SNAP
;
449 if (strncasecmp("dot1q", d
, 10)==0) ret
|= MOPS_dot1Q
;
451 if (strncasecmp("mpls", d
, 10)==0) ret
|= MOPS_MPLS
;
453 if (strncasecmp("ip", d
, 10)==0) ret
|= MOPS_IP
;
455 if (strncasecmp("udp", d
, 10)==0) ret
|= MOPS_UDP
;
457 if (strncasecmp("tcp", d
, 10)==0) ret
|= MOPS_TCP
;
459 return -1; // unknown
460 tok
=strtok(NULL
, " ");
465 // Returns one of 'enum fieldtypes' for a given ascii string
466 // or -1 if unknown field type given.
467 int amp_str2type(char *d
)
469 if (strncasecmp("byte8", d
, 10)==0) return Byte8
;
470 if (strncasecmp("byte16", d
, 10)==0) return Byte16
;
471 if (strncasecmp("byte32", d
, 10)==0) return Byte32
;
472 if (strncasecmp("flaginbyte", d
, 16)==0) return Flag_in_Byte
;
473 if (strncasecmp("multibytes", d
, 16)==0) return MultiBytes
;
474 if (strncasecmp("multibyteshex", d
, 16)==0) return MultiBytesHex
;
475 if (strncasecmp("tlv", d
, 10)==0) return TLV
;
479 // Converts integer field types into ascii string s[32].
480 // Returns 0 upon success, 1 if unknown type
481 int amp_type2str(int t
, char *s
)
485 mz_strncpy(s
, "Byte8", 32);
488 mz_strncpy(s
, "Byte16", 32);
491 mz_strncpy(s
, "Byte32", 32);
494 mz_strncpy(s
, "FlagInByte", 32);
497 mz_strncpy(s
, "MultiBytes", 32);
500 mz_strncpy(s
, "MultiBytesHex", 32);
503 mz_strncpy(s
, "TLV", 32);
506 mz_strncpy(s
, "[unknown/same]", 32);
513 // Searches the automops object with specified name 'd'.
514 // NOTE: The names are case insensitive!
516 // RETURN VALUE: pointer to that object
517 // or NULL if not found
519 struct automops
* amp_getamp_byname(struct automops
*head
, char *d
)
524 if (strncasecmp(a
->name
, d
, AUTOMOPS_MAX_NAME_LEN
)==0) return a
;
527 return NULL
; // not found
531 // Add data 'd' identified by tag 'xntag' to the automops entry 'amp'.
533 // RETURN VALUE: 0 upon success, 1 upon failure
535 int amp_add_pentry (struct automops
*amp
, int xntag
, char *d
)
539 u_int8_t x
[MAX_MOPS_MSG_SIZE
];
544 if (strpbrk(d
," \t")!=NULL
) return ampInvalidName
; // name must not consist of multiple words!
545 g
= amp_getamp_byname(amp_head
, d
);
546 if (g
!=NULL
) return ampDuplicateName
; // name already exists!
547 mz_strncpy(amp
->name
, d
, AUTOMOPS_MAX_NAME_LEN
);
549 fprintf(stderr
, "Adding protocol '%s'\n", amp
->name
);
554 mz_strncpy(amp
->desc
, d
, AUTOMOPS_MAX_SHORTDESC_LEN
);
558 i
= mops_str2layers(d
);
559 if (i
==-1) return ampInvalidLayer
;
560 if ((i
&MOPS_UDP
) && (i
&MOPS_TCP
)) return ampTCPandUDP
; // cannot require both!
561 amp
->layers_on
|= i
; // must be ORed because several same-tags allowed
565 i
= mops_str2layers(d
);
566 if (i
==-1) return ampInvalidLayer
;
567 amp
->layers_off
|= i
; // must be ORed because several same-tags allowed
570 case xml_payloadtype
: // 0=none, 1=ascii, 2=hex, 3=any
571 tok
= strtok (d
," ");
573 if (strncasecmp("allowed", d
, 10)==0) {
574 // only change if payload_type is still zero
575 if (amp
->payload_type
==0) amp
->payload_type
=3;
577 if (strncasecmp("ascii", d
, 10)==0) amp
->payload_type
|=1;
579 if (strncasecmp("hex", d
, 10)==0) amp
->payload_type
|=2;
581 if (strncasecmp("any", d
, 10)==0) amp
->payload_type
=3;
583 if (strncasecmp("none", d
, 10)==0) amp
->payload_type
=0;
584 else return ampPayloadType
; // unknown
585 tok
=strtok(NULL
, " ");
590 i
=strnlen(d
,MAX_MOPS_MSG_SIZE
);
591 if (i
==MAX_MOPS_MSG_SIZE
) return ampPayloadLen
;
592 amp
->payload
= (char*) malloc (i
+1);
593 mz_strncpy(amp
->payload
, d
, i
+1);
598 i
=str2hex(d
,x
,MAX_MOPS_MSG_SIZE
);
599 if (i
==MAX_MOPS_MSG_SIZE
) return ampPayloadLen
;
601 amp
->payload
= (char*) malloc (i
+1);
602 memcpy((void*)amp
->payload
, (void*) x
, i
);
607 return ampUnknownTag
;
613 // Checks if given index value would be valid for the specified amp.
614 // (Index values must increase monotonic, successive same-values are
615 // allowed, step size is 0 or 1 but not greater. First index value
616 // must be 1. Example: 1,2,2,2,3,4,5,5,5,5,5,6,7,7,7.)
618 // RETURN VALUE: 0 if ok, 1 if wrong
620 int amp_checkindex(struct automops
*amp
, int i
)
623 struct fields
*g
, *h
=NULL
;
626 while (g
!=NULL
) { // jump to last field object P->F1->F2->NULL
627 if (g
->index
==0) break; // stop if empty field object found
630 } // now h is the penultimate object
631 // printf("CHECKINDEX: try for %i, amp='%s' -- field '%s', index %i, [%i]\n",
632 // i, amp->name, h->name, h->index, h->i);
633 if (h
==NULL
) return 0; // first element, so any i is ok
635 if (i
<last_i
) return 1; // index is decreasing!
636 if ((i
-last_i
)>1) return 1; // index increase step larger 1!
642 // Searches the field object with specified name 'd'.
643 // NOTE: The names ar case insensitive!
645 // RETURN VALUE: pointer to that object
646 // or NULL if not found
648 struct fields
* amp_getfield_byname(struct automops
*amp
, char *d
)
655 if (strncasecmp(f
->name
, d
, AUTOMOPS_MAX_NAME_LEN
)==0) return f
;
658 return NULL
; // not found
663 // This strange function ensures that 'w' consists of a single word.
664 // If 'w' consists of multiple words, it removes all but the first
665 // word. Additionally surrounding spaces are removed.
667 // RETURN VALUE: number of words found
669 // EXAMPLE: "Hello world" => "Hello"
670 // (return value = 2)
672 int ensure_single_word(char *w
)
683 mz_strncpy(w
, t0
, AUTOMOPS_MAX_NAME_LEN
);
690 // Add data 'd' identified by tag 'xntag' to the field entry 'f'
691 int amp_add_fentry (struct automops
*amp
, struct fields
*f
, int xntag
, char *d
)
694 unsigned long long int ulli
=0;
695 struct fields
*g
=NULL
;
699 i
= (int) str2int(d
);
700 if (amp_checkindex(amp
, i
)) return ampInvalidIndex
; // invalid index
705 if (ensure_single_word(d
)>1) return ampInvalidName
; // name must be single word
706 g
= amp_getfield_byname(amp
, d
);
707 if (g
!=NULL
) return 1; // name already exists
708 mz_strncpy(f
->name
, d
, AUTOMOPS_MAX_NAME_LEN
);
712 mz_strncpy(f
->shortdesc
, d
, AUTOMOPS_MAX_SHORTDESC_LEN
);
717 if (i
==400) return ampDescTooLong
;
718 f
->longdesc
= (char*) malloc(i
+1);
719 mz_strncpy(f
->longdesc
, d
, i
+1);
724 if (i
==-1) return ampInvalidType
;
729 if (strncasecmp(d
, "yes", 6)==0) f
->constant
=1;
731 if (strncasecmp(d
, "no", 6)==0) f
->constant
=0;
732 else return ampUnknownKeyword
; // unknown keyword
736 if (ensure_single_word(d
)>1) return ampSingleWordRequired
; // name must be single word
737 i
= strnlen(d
, AUTOMOPS_MAX_NAME_LEN
);
738 if (i
==AUTOMOPS_MAX_NAME_LEN
) return 1; // too long
739 mz_strncpy(f
->valname
, d
, AUTOMOPS_MAX_NAME_LEN
);
744 if (ulli
>0xffffffff) return ampRangeError
;
745 f
->val
= (u_int32_t
) ulli
;
750 if (ulli
>0xffffffff) return ampRangeError
;
751 f
->min
= (u_int32_t
) ulli
;
756 if (ulli
>0xffffffff) return ampRangeError
;
757 if (ulli
<f
->min
) return 1; // max must be greater or equal min
758 f
->max
= (u_int32_t
) ulli
;
763 if (ulli
>0xffffffff) return ampRangeError
;
764 f
->tlv_type
= (u_int32_t
) ulli
;
769 if (ulli
>0xffffffff) return ampRangeError
;
770 f
->tlv_len
= (u_int32_t
) ulli
;
774 i
= (int) str2int(d
);
775 if (i
>7) return ampRangeError
;
780 return ampUnknownTag
; // unknown tag
786 // Delete linked list of field elements for a given automops
787 // Returns the number of deleted elements
788 int automops_delete_fields (struct automops
*amp
)
790 struct fields
* cur
= amp
->field
;
794 if (cur
==NULL
) return 0;
800 if (tmp
->str
!=NULL
) {
805 if (tmp
->longdesc
!=NULL
) {
821 // Deletes all elements except the specified element which us usually
822 // the head element. Also 'used' elements will be removed!
824 void automops_delete_all (struct automops
*list
)
826 struct automops
*head
= list
;
827 struct automops
*cur
= list
->next
;
828 struct automops
*tmp
;
830 // Delete all but head element:
835 fprintf(stderr
, " Deleting '%s'\n",cur
->name
);
837 automops_delete_protocol(cur
);
844 fprintf(stderr
, " Deleting '%s'\n",head
->name
);
847 if (head
->payload_s
) {
848 if (head
->payload
!=NULL
) {
849 free (head
->payload
);
853 automops_set_defaults(head
);
857 // Completely clean up.
858 // After that, there is no automops list anymore.
859 // You only need this function when stopping mausezahn.
861 void automops_cleanup (struct automops
*list
)
863 // 1) delete all elements except head:
864 automops_delete_all(list
);
867 automops_delete_fields (list
);
868 if (list
->payload_s
) {
869 if (list
->payload
!=NULL
) {
870 free (list
->payload
);
880 // Converts amperr error values in 'e' to string messages 's'
881 // which must be at least 64 bytes in size.
883 // RETURN VALUE: 0 if convertable, 1 else
885 int amperr2str (int e
, char *s
)
891 case ampInvalidIndex
:
892 mz_strncpy(s
, "invalid index", 64);
895 mz_strncpy(s
, "invalid name", 64);
898 case ampDuplicateName
:
899 mz_strncpy(s
, "duplicate name", 64);
903 mz_strncpy(s
, "description too long", 64);
906 case ampInvalidLayer
:
907 mz_strncpy(s
, "invalid layer", 64);
911 mz_strncpy(s
, "either TCP or UDP", 64);
916 mz_strncpy(s
, "invalid type", 64);
919 case ampUnknownKeyword
:
920 mz_strncpy(s
, "unknown keyword", 64);
923 case ampSingleWordRequired
:
924 mz_strncpy(s
, "single word required", 64);
928 mz_strncpy(s
, "invalid range", 64);
932 mz_strncpy(s
, "invalid payload type", 64);
936 mz_strncpy(s
, "payload length exceeded", 64);
941 mz_strncpy(s
, "unknown tag (check mausezahn version?)", 64);
945 mz_strncpy(s
, "completely unknown cause", 64);
954 // Open amp file (containing XML data describing one or more protocols for automops)
955 // and copy the data into a char array.
957 // NOTE that the char array must be free'd by the caller.
959 // RETURN VALUE: - pointer to char array with the XML data
960 // - NULL upon failure
962 char * mapfile (char *fn
)
969 fd
= fopen (fn
, "r");
970 if (fd
==NULL
) return NULL
;
972 // Determine length of file
973 (void) fseek(fd
, 0L, SEEK_END
);
975 if (fn_s
> AUTOMOPS_MAX_FILE_SIZE
) {
976 fprintf(stderr
, " File '%s' exceeds max allowed length (%lu>%i)\n",
977 fn
, fn_s
, AUTOMOPS_MAX_FILE_SIZE
);
981 if (verbose
) fprintf(stderr
, " Parsing %lu bytes from '%s'...\n", fn_s
, fn
);
984 blob
= (char*) malloc(fn_s
+1);
991 while ((c
=fgetc(fd
)) != EOF
) {
995 fprintf(stderr
, " WARNING: parsing '%s' exceeded EOF\n", fn
);
996 break; // should not reach here
1006 // Create automops PDU within *mp based on data in *amp
1008 int automops_update (struct mops
*mp
, struct automops
*amp
)