make: fix access to env vars
[netsniff.git] / src / automops.c
blobb46534603056dcb6d542a68c932b6dce02854e4f
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
4 *
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.
8 *
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
12 * details.
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
19 #include "mz.h"
20 #include "mops.h"
23 // Creates first element, aka "head" element
24 // This element can also be used! See automops_alloc_protocol!
25 //
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
34 return new_automops;
39 // (Re-)sets anything within the specified automops element
40 void automops_set_defaults(struct automops * cur)
42 int i;
44 mz_strncpy(cur->name, "user_proto", 16);
45 mz_strncpy(cur->desc, "undefined", 16);
46 cur->layers_on = 0;
47 cur->layers_off = 0;
49 cur->etype = 0;
50 cur->proto = 0;
51 for (i=0; i<6; i++) {
52 cur->sa[i] = 0x00;
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
59 cur->payload = NULL;
60 cur->payload_s = 0;
61 cur->defined_externally = -1; // undefined
62 if (cur->field != NULL) automops_delete_fields (cur);
63 cur->field = NULL;
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
73 //
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);
94 new_automops->used=0;
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;
102 return 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.
112 // RETURN VALUE:
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? /////
126 if (cur->used>0) {
127 return NULL;
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);
139 return NULL;
142 // part of linked list
143 last = cur->prev;
144 cur->next->prev = cur->prev;
145 cur->prev->next = cur->next;
146 if (cur==amp_head) {
147 amp_head = last;
149 if (cur!=NULL) free (cur);
151 return last;
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;
166 do {
167 if ( (strncasecmp(name, cur->name,
168 AUTOMOPS_MAX_NAME_LEN) == 0)) {
169 return cur; // FOUND!
171 cur = cur->next;
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];
189 uint32_t SA=0, DA=0;
190 uint8_t *x, *y;
191 char bits_on[18], bits_off[18];
192 int i=0, j=0;
194 do {
195 if (cur->used==-1) {
196 fprintf(stderr, "AUTOMOPS: Initial element\n");
197 if ((cur->next==cur)&&(cur->prev==cur))
198 fprintf(stderr, " No other elements found.\n");
199 break;
201 if (cur->used>0) used++;
202 anzmops++;
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));
220 } else {
221 fprintf(stderr, " IP: ---\n");
223 // Walk through field data:
224 f=cur->field; j=0;
225 while (f!=NULL) {
226 j++; // count number of fields
227 if (verbose) {
228 i=0;
229 if (f->longdesc!=NULL) {
230 mz_strncpy(str, f->longdesc, 60);
231 if (strnlen(str,60)>=59) i=1;
233 else {
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);
251 f=f->next;
253 if (verbose==0) fprintf(stderr, " %i fields defined.\n", j);
254 //---------------------------------
255 cur = cur->next;
256 } while (head != cur);
258 return used;
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;
273 int i;
275 // Allocate memory
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));
320 if (g==NULL) {
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;
326 h = g;
327 } else { // next elements
328 h->next = g;
329 h = g;
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);
344 if (f->str_s) {
345 h->str_s = f->str_s;
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;
354 h->type = f->type;
355 h->tlv_type = f->tlv_type;
356 h->tlv_len = f->tlv_len;
357 h->val = f->val;
358 h->min = f->min;
359 h->max = f->max;
360 h->leftshift = f->leftshift;
361 h->index = f->index;
363 return new_automops;
367 // Add a new field object
368 struct fields * automops_add_field (struct automops *amp)
370 struct fields *f, *f_prev=NULL, *g;
371 int i=0;
373 // jump to the end of the fields list
374 f=amp->field;
375 while (f!=NULL) {
376 f_prev=f;
377 ++i;
378 f=f->next;
381 g = (struct fields *) malloc(sizeof(struct fields));
382 if (g==NULL) {
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
388 amp->field = g;
389 } else { // it is just another element in the fields list
390 f_prev->next = g;
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);
396 return 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)
404 f->name[0]=0x00;
405 f->shortdesc[0]=0x00;
406 f->longdesc=NULL;
407 f->constant=0;
409 //NOTE: f->i MUST NOT be reset!
410 f->index=0;
411 f->valname[0]=0x00;
412 f->tlv_type=0;
413 f->tlv_len=0;
414 f->val=0;
415 f->min=0;
416 f->max=0;
417 f->leftshift=0;
418 f->str=NULL;
419 f->str_s=0;
420 f->next=NULL;
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.
432 // RETURN VALUE:
433 // The sum of basic protocols
434 // or -1 upon failure.
435 int mops_str2layers(char *d)
437 int ret=0;
438 char *tok;
440 // dissalow too long strings.
441 if (strlen(d)>50) return -1; // TODO: replace 100 to a more reasonable value
443 tok=strtok(d, " ");
444 while (tok!=NULL) {
445 if (strncasecmp("eth", d, 10)==0) ret |= MOPS_ETH;
446 else
447 if (strncasecmp("snap", d, 10)==0) ret |= MOPS_SNAP;
448 else
449 if (strncasecmp("dot1q", d, 10)==0) ret |= MOPS_dot1Q;
450 else
451 if (strncasecmp("mpls", d, 10)==0) ret |= MOPS_MPLS;
452 else
453 if (strncasecmp("ip", d, 10)==0) ret |= MOPS_IP;
454 else
455 if (strncasecmp("udp", d, 10)==0) ret |= MOPS_UDP;
456 else
457 if (strncasecmp("tcp", d, 10)==0) ret |= MOPS_TCP;
458 else
459 return -1; // unknown
460 tok=strtok(NULL, " ");
462 return ret;
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;
476 return -1;
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)
483 switch (t) {
484 case Byte8:
485 mz_strncpy(s, "Byte8", 32);
486 break;
487 case Byte16:
488 mz_strncpy(s, "Byte16", 32);
489 break;
490 case Byte32:
491 mz_strncpy(s, "Byte32", 32);
492 break;
493 case Flag_in_Byte:
494 mz_strncpy(s, "FlagInByte", 32);
495 break;
496 case MultiBytes:
497 mz_strncpy(s, "MultiBytes", 32);
498 break;
499 case MultiBytesHex:
500 mz_strncpy(s, "MultiBytesHex", 32);
501 break;
502 case TLV:
503 mz_strncpy(s, "TLV", 32);
504 break;
505 default:
506 mz_strncpy(s, "[unknown/same]", 32);
507 return 1;
509 return 0;
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)
521 struct automops *a;
522 a = head;
523 do {
524 if (strncasecmp(a->name, d, AUTOMOPS_MAX_NAME_LEN)==0) return a;
525 a=a->next;
526 } while (a!=head);
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)
537 int i=0;
538 char *tok;
539 u_int8_t x[MAX_MOPS_MSG_SIZE];
540 struct automops *g;
542 switch (xntag) {
543 case xml_name:
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);
548 if (verbose==2) {
549 fprintf(stderr, "Adding protocol '%s'\n", amp->name);
551 break;
553 case xml_desc:
554 mz_strncpy(amp->desc, d, AUTOMOPS_MAX_SHORTDESC_LEN);
555 break;
557 case xml_requires:
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
562 break;
564 case xml_conflicts:
565 i = mops_str2layers(d);
566 if (i==-1) return ampInvalidLayer;
567 amp->layers_off |= i; // must be ORed because several same-tags allowed
568 break;
570 case xml_payloadtype: // 0=none, 1=ascii, 2=hex, 3=any
571 tok = strtok (d," ");
572 while (tok!=NULL) {
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;
576 } else
577 if (strncasecmp("ascii", d, 10)==0) amp->payload_type|=1;
578 else
579 if (strncasecmp("hex", d, 10)==0) amp->payload_type|=2;
580 else
581 if (strncasecmp("any", d, 10)==0) amp->payload_type=3;
582 else
583 if (strncasecmp("none", d, 10)==0) amp->payload_type=0;
584 else return ampPayloadType; // unknown
585 tok=strtok(NULL, " ");
587 break;
589 case xml_payload:
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);
594 amp->payload_s = i;
595 break;
597 case xml_payloadhex:
598 i=str2hex(d,x,MAX_MOPS_MSG_SIZE);
599 if (i==MAX_MOPS_MSG_SIZE) return ampPayloadLen;
600 if (i==-1) return 1;
601 amp->payload = (char*) malloc (i+1);
602 memcpy((void*)amp->payload, (void*) x, i);
603 amp->payload_s = i;
604 break;
606 default:
607 return ampUnknownTag;
610 return 0;
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)
622 int last_i=0;
623 struct fields *g, *h=NULL;
625 g=amp->field;
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
628 h=g;
629 g=g->next;
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
634 last_i=h->index;
635 if (i<last_i) return 1; // index is decreasing!
636 if ((i-last_i)>1) return 1; // index increase step larger 1!
637 return 0;
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)
650 struct fields *f;
652 f = amp->field;
654 while (f!=NULL) {
655 if (strncasecmp(f->name, d, AUTOMOPS_MAX_NAME_LEN)==0) return f;
656 f=f->next;
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)
674 char *t, *t0;
675 int i=0;
677 t=strtok(w," ");
678 t0=t;
679 while (t!=NULL) {
680 i++;
681 t=strtok(NULL, " ");
683 mz_strncpy(w, t0, AUTOMOPS_MAX_NAME_LEN);
684 return i;
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)
693 int i=0;
694 unsigned long long int ulli=0;
695 struct fields *g=NULL;
697 switch(xntag) {
698 case xml_index:
699 i = (int) str2int(d);
700 if (amp_checkindex(amp, i)) return ampInvalidIndex; // invalid index
701 f->index = (int) i;
702 break;
704 case xml_name:
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);
709 break;
711 case xml_desc:
712 mz_strncpy(f->shortdesc, d, AUTOMOPS_MAX_SHORTDESC_LEN);
713 break;
715 case xml_longdesc:
716 i = strnlen(d, 400);
717 if (i==400) return ampDescTooLong;
718 f->longdesc = (char*) malloc(i+1);
719 mz_strncpy(f->longdesc, d, i+1);
720 break;
722 case xml_type:
723 i = amp_str2type(d);
724 if (i==-1) return ampInvalidType;
725 f->type = i;
726 break;
728 case xml_constant:
729 if (strncasecmp(d, "yes", 6)==0) f->constant=1;
730 else
731 if (strncasecmp(d, "no", 6)==0) f->constant=0;
732 else return ampUnknownKeyword; // unknown keyword
733 break;
735 case xml_valname:
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);
740 break;
742 case xml_value:
743 ulli = str2lint(d);
744 if (ulli>0xffffffff) return ampRangeError;
745 f->val = (u_int32_t) ulli;
746 break;
748 case xml_min:
749 ulli = str2lint(d);
750 if (ulli>0xffffffff) return ampRangeError;
751 f->min = (u_int32_t) ulli;
752 break;
754 case xml_max:
755 ulli = str2lint(d);
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;
759 break;
761 case xml_tlvt:
762 ulli = str2lint(d);
763 if (ulli>0xffffffff) return ampRangeError;
764 f->tlv_type = (u_int32_t) ulli;
765 break;
767 case xml_tlvl:
768 ulli = str2lint(d);
769 if (ulli>0xffffffff) return ampRangeError;
770 f->tlv_len = (u_int32_t) ulli;
771 break;
773 case xml_lshift:
774 i = (int) str2int(d);
775 if (i>7) return ampRangeError;
776 f->leftshift=i;
777 break;
779 default:
780 return ampUnknownTag; // unknown tag
782 return 0;
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;
791 struct fields * tmp;
792 int i=0;
794 if (cur==NULL) return 0;
796 do {
797 tmp = cur;
798 cur = cur->next;
799 if (tmp->str_s) {
800 if (tmp->str!=NULL) {
801 free (tmp->str);
802 tmp->str=NULL;
805 if (tmp->longdesc!=NULL) {
806 free(tmp->longdesc);
807 tmp->longdesc=NULL;
809 if (tmp!=NULL) {
810 free(tmp);
811 tmp=NULL;
813 i++;
814 } while (cur!=NULL);
816 return i;
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:
831 while (head != cur)
833 tmp = cur->next;
834 if (verbose) {
835 fprintf(stderr, " Deleting '%s'\n",cur->name);
837 automops_delete_protocol(cur);
838 cur = tmp;
840 head->next = head;
841 head->prev = head;
843 if (verbose) {
844 fprintf(stderr, " Deleting '%s'\n",head->name);
847 if (head->payload_s) {
848 if (head->payload!=NULL) {
849 free (head->payload);
850 head->payload=NULL;
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);
866 // 2) delete head:
867 automops_delete_fields (list);
868 if (list->payload_s) {
869 if (list->payload!=NULL) {
870 free (list->payload);
871 list->payload=NULL;
874 if (list!=NULL) {
875 free(list);
876 list=NULL;
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)
887 switch (e) {
889 case ampSuccess:
890 break;
891 case ampInvalidIndex:
892 mz_strncpy(s, "invalid index", 64);
893 break;
894 case ampInvalidName:
895 mz_strncpy(s, "invalid name", 64);
896 break;
898 case ampDuplicateName:
899 mz_strncpy(s, "duplicate name", 64);
900 break;
902 case ampDescTooLong:
903 mz_strncpy(s, "description too long", 64);
904 break;
906 case ampInvalidLayer:
907 mz_strncpy(s, "invalid layer", 64);
908 break;
910 case ampTCPandUDP:
911 mz_strncpy(s, "either TCP or UDP", 64);
912 break;
915 case ampInvalidType:
916 mz_strncpy(s, "invalid type", 64);
917 break;
919 case ampUnknownKeyword:
920 mz_strncpy(s, "unknown keyword", 64);
921 break;
923 case ampSingleWordRequired:
924 mz_strncpy(s, "single word required", 64);
925 break;
927 case ampRangeError:
928 mz_strncpy(s, "invalid range", 64);
929 break;
931 case ampPayloadType:
932 mz_strncpy(s, "invalid payload type", 64);
933 break;
935 case ampPayloadLen:
936 mz_strncpy(s, "payload length exceeded", 64);
937 break;
940 case ampUnknownTag:
941 mz_strncpy(s, "unknown tag (check mausezahn version?)", 64);
942 break;
944 default:
945 mz_strncpy(s, "completely unknown cause", 64);
946 return 1;
948 return 0;
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)
964 int i, c;
965 long fn_s;
966 FILE *fd;
967 char *blob;
969 fd = fopen (fn, "r");
970 if (fd==NULL) return NULL;
972 // Determine length of file
973 (void) fseek(fd, 0L, SEEK_END);
974 fn_s = ftell(fd);
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);
978 fclose(fd);
979 return NULL;
981 if (verbose) fprintf(stderr, " Parsing %lu bytes from '%s'...\n", fn_s, fn);
982 rewind(fd);
984 blob = (char*) malloc(fn_s+1);
985 if (blob==NULL) {
986 fclose(fd);
987 return NULL;
990 i=0;
991 while ((c=fgetc(fd)) != EOF) {
992 blob[i]=(char) c;
993 i++;
994 if (i>fn_s) {
995 fprintf(stderr, " WARNING: parsing '%s' exceeded EOF\n", fn);
996 break; // should not reach here
999 fclose(fd);
1000 blob[i]='\0';
1001 return blob;
1006 // Create automops PDU within *mp based on data in *amp
1008 int automops_update (struct mops *mp, struct automops *amp)
1011 return 0;