source: libpacketdump/parser/parser.y @ 49e3fff

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 49e3fff was f6c2d8d, checked in by Perry Lorier <perry@…>, 15 years ago

Don't try and continue to decode a snapped packet.
Lots of warning cleanups.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1%{
2    #include <stdio.h>
3    #include <stdlib.h>
4    #include <string.h>
5    #include <netinet/in.h>
6    #include <sys/socket.h>
7    #include <arpa/inet.h>
8    #include <assert.h>
9    #include "parser.h"
10    #include "libpacketdump.h"
11
12    #define YYERROR_VERBOSE 1
13
14    typedef uint64_t bitbuffer_t;
15   
16    int yylex(void);
17    int yyerror(char *s);
18    element_t *append(element_t *list, element_t *item);
19    void print_list(element_t *list);
20
21    extern FILE* yyin;
22    extern char* yytext;
23    extern int lines;
24    char *file;
25    element_t *el_list = NULL;
26
27    /* i didnt want these to be global, but i think they have to be? :/ */
28    static bitbuffer_t buffer = 0;
29    static int bits = 0;
30%}
31
32
33%union {
34    int intval;
35    char *textval;
36    element_t *ptr;
37}
38
39%token TOK_BIGENDIAN TOK_LITTLEENDIAN TOK_NEXT TOK_OUTPUT_INT TOK_OUTPUT_HEX TOK_OUTPUT_IPV4 TOK_OUTPUT_FLAG TOK_CONSTANT TOK_IDENTIFIER TOK_OUTPUT_MAC TOK_OUTPUT_NONE
40
41%type <intval> TOK_BIGENDIAN TOK_LITTLEENDIAN TOK_NEXT TOK_OUTPUT_INT TOK_OUTPUT_HEX TOK_OUTPUT_IPV4 TOK_OUTPUT_FLAG TOK_OUTPUT_NONE TOK_CONSTANT output byteorder size '"'
42%type <textval> TOK_IDENTIFIER identifier
43%type <ptr> element nextfile elements
44
45%%
46
47config:     elements nextfile { /*print_list(el_list);*/ }
48           ;
49       
50elements:   element
51          | elements element { }
52          ;
53
54element:    byteorder size output identifier {
55                node_t *n;
56                element_t *el;
57                /* create a new field node... */
58                field_t *new_field = (field_t *)malloc(sizeof(field_t));
59                new_field->order = $1;
60                new_field->size = $2;
61                new_field->display = $3;
62                new_field->identifier = $4;
63
64                /* to go inside a new node... */
65                n = (node_t *)malloc(sizeof(node_t));
66                n->field = new_field;
67
68                /* to go inside a new element */
69                el = (element_t *)malloc(sizeof(element_t));           
70                el->type = FIELD;
71                el->next = NULL;
72                el->data = n;
73               
74                /* and stick the new element on the end of our list */
75                el_list = append(el_list, el);
76            }
77          ;
78
79byteorder: TOK_BIGENDIAN { $$ = BIGENDIAN; }
80            | TOK_LITTLEENDIAN { $$ = LITTLEENDIAN; }
81          ;
82
83size:   TOK_CONSTANT { $$ = yylval.intval; }
84        ;
85
86output:   TOK_OUTPUT_HEX    { $$ = DISPLAY_HEX; }
87        | TOK_OUTPUT_INT    { $$ = DISPLAY_INT; }
88        | TOK_OUTPUT_IPV4   { $$ = DISPLAY_IPV4; }
89        | TOK_OUTPUT_FLAG   { $$ = DISPLAY_FLAG; }
90        | TOK_OUTPUT_MAC    { $$ = DISPLAY_MAC; }
91        | TOK_OUTPUT_NONE   { $$ = DISPLAY_NONE; }
92        ;
93
94
95identifier: TOK_IDENTIFIER { $$ = strdup($1); }
96            ;
97
98
99nextfile:   TOK_NEXT identifier identifier {
100
101                element_t *tmp;
102                node_t *n;
103                element_t *el;
104                next_t *nextheader = (next_t *)malloc(sizeof(next_t));
105                nextheader->prefix = $2;
106                nextheader->fieldname = $3;
107                nextheader->target = NULL;
108               
109                for(tmp = el_list ;; tmp=tmp->next)
110                {
111                    /*
112                     * if we hit the end of the list or a nextheader then
113                     * the field name we are looking for doesn't exist
114                     * - this is an error but we can carry on and just
115                     * not bother parsing anything after this header
116                     */
117                    if(tmp == NULL || tmp->type == NEXTHEADER)
118                    {
119                        fprintf(stderr, "XXX No field match found for "
120                                        "nextfield '%s'...ignoring\n", $3);
121                        $$ = NULL;
122                        break;
123                    }
124                   
125                    /*
126                     * if the field name matches the one we are looking at,
127                     * store a pointer to it so we can steal its value later
128                     */
129                    if(strcmp($3, tmp->data->field->identifier) == 0)
130                    {
131                        nextheader->target = tmp->data->field;
132                        break;
133                    }
134                }
135               
136                n = (node_t *)malloc(sizeof(node_t));
137                n->nextheader = nextheader;
138
139                el = (element_t *)malloc(sizeof(element_t));           
140                el->type = NEXTHEADER;
141                el->next = NULL;
142                el->data = n;
143               
144                el_list = append(el_list, el);
145            }
146        |   { /*printf("no next file...\n");*/ $$ = NULL; }
147        ;
148
149
150%%
151
152element_t* parse_protocol_file(char *filename)
153{
154    /* hold onto this so we can put it in any error messages */
155    file = filename;
156
157    /* if the protocol file doesn't exist, we return null and
158     * it will fall back to using the generic_decode function
159     */
160    yyin = fopen(filename, "r");
161    if(!yyin)
162        return NULL;
163
164    el_list = NULL;
165    lines = 1;
166
167    yyparse();
168    fclose(yyin);
169    return el_list;
170}
171
172
173
174bitbuffer_t getbit(void **packet, int *packlen, uint64_t numbits)
175{
176    bitbuffer_t ret;
177    bitbuffer_t one = 1;
178
179    /* While the buffer is not filled up and there is still
180     * data in the packet to read, read a byte...
181     *
182     * The buffer gets filled from right to left
183     */
184    while(bits < (sizeof(bitbuffer_t)-1)*8 && *packlen > 0)
185    {
186        /* read in one byte from the packet */
187        buffer |= ((*  ((bitbuffer_t*)*packet)   )&0xff) << bits;
188        /* update the position within the packet */
189        *packet = ((char*)*packet) + 1;
190
191        bits += 8;
192        *packlen -= 1;
193    }
194
195    /* our return value is the last <numbits> of the buffer */
196    ret = buffer & (   (one<<numbits)   -1);
197   
198    /* remove the bits that are being returned from out buffer */
199    buffer >>= numbits;
200
201    /* and update our position inside this buffer */
202    bits -= numbits;
203
204    return ret;
205}
206
207
208bitbuffer_t fix_byteorder(bitbuffer_t value, enum byte_order_t order, uint64_t size)
209{
210    bitbuffer_t one = 1;
211    bitbuffer_t lhs;
212    bitbuffer_t rhs;;
213
214    /*
215     * XXX trial and error seems to show these numbers to work.
216     * I've tried fields of length 1,2,3,4,8,13,16,32 and they seem to work.
217     * Others are untested...
218     */
219    switch(order)
220    {
221        case BIGENDIAN:
222            if(size < 16)
223                return value;
224            if(size < 32)
225                return ntohs(value);
226            if(size <= 32)
227                return ntohl(value);
228           
229            lhs = ntohl(value& ((one<<32)-1));
230            rhs = ntohl(value >> 32);
231            return ((lhs<<32) | rhs);
232
233        case LITTLEENDIAN:
234            return value;
235
236    };
237
238    /* should never get here */
239    assert(0);
240    return 0;
241}
242
243
244
245void decode_protocol_file(uint16_t link_type,char *packet,int len,element_t *el)
246{
247    bitbuffer_t result;
248
249    while(el != NULL)
250    {
251        switch(el->type)
252        {
253            case FIELD:
254                if (len*8+bits<el->data->field->size) {
255                        printf(" [Truncated]\n");
256                        return;
257                }
258                result = getbit((void*)&packet, &len, el->data->field->size);
259
260                switch(el->data->field->display)
261                {
262                    /* integers get byteswapped if needed and displayed */
263                    case DISPLAY_INT:
264                    {
265                        result = fix_byteorder(result,
266                                el->data->field->order,
267                                el->data->field->size);
268                               
269                        el->data->field->value = result;
270                        printf(" %s %lld\n",
271                                el->data->field->identifier,
272                                result);
273                    }
274                    break;
275
276                    /*
277                     * hex numbers get byteswapped if needed and displayed
278                     * without being padded with zeroes
279                     */
280                    case DISPLAY_HEX:
281                    {
282                        result = fix_byteorder(result,
283                                el->data->field->order,
284                                el->data->field->size);
285                       
286                        el->data->field->value = result;
287                        printf(" %s 0x%llx\n",
288                                el->data->field->identifier,
289                                result);
290                    }
291                    break;
292                   
293                    /*
294                     * ipv4 addresses stay in network byte order and are
295                     * given to inet_ntoa() to deal with
296                     */
297                    case DISPLAY_IPV4:
298                    {
299                        /* assumes all ipv4 addresses are 32bit fields */
300                        struct in_addr address;
301                        address.s_addr = (uint32_t)result;
302                        el->data->field->value = result;
303                   
304                        printf(" %s %s\n",
305                                el->data->field->identifier,
306                                inet_ntoa(address));
307                    }
308                    break;
309
310                    /*
311                     * mac addresses stay in network byte order and are
312                     * displayed byte by byte with zero padding
313                     */
314                    case DISPLAY_MAC:
315                    {
316                        /* assumes all mac addresses are 48bit fields */
317                        uint8_t *ptr = (uint8_t*)&result;
318                        el->data->field->value = result;
319                        printf(" %s %02x:%02x:%02x:%02x:%02x:%02x\n",
320                                el->data->field->identifier,
321                                ptr[0], ptr[1], ptr[2],
322                                ptr[3], ptr[4], ptr[5]);
323                    }
324                    break;
325                   
326                    /*
327                     * Flag values are only displayed if their value is true
328                     * otherwise they are ignored
329                     */
330                    case DISPLAY_FLAG:
331                    {
332                        el->data->field->value = result;
333                        if(result)
334                            printf(" %s\n", el->data->field->identifier);
335                    }
336                    break;
337
338                    /*
339                     * Hidden values are not displayed at all. This is useful
340                     * for reserved fields or information that you don't care
341                     * about but need to read in order to get to the rest of
342                     * the header
343                     */
344                    case DISPLAY_NONE:
345                    {
346                        result = fix_byteorder(result,
347                                el->data->field->order,
348                                el->data->field->size);
349                        el->data->field->value = result;
350                    }
351                    break;
352                };
353
354                break;
355
356            case NEXTHEADER:
357                /*
358                 * Before we move on to the next header, make sure our packet
359                 * pointer is pointing to the first unused bytes. This may
360                 * mean we have to backtrack to some that were put into the
361                 * buffer but weren't used.
362                 * - This wouldn't be a problem if all future output came
363                 * from this buffer, but there is a good chance we will use
364                 * some code from a shared library to output packet info
365                 * instead, and this doesn't have access to the buffer.
366                 */
367                packet = packet - (bits / 8);
368                len = len + (bits / 8);
369                bits = 0;
370                buffer = 0;
371
372                decode_next(packet, len, el->data->nextheader->prefix,
373                        el->data->nextheader->target->value);
374                break;
375        };
376       
377        el = el->next;
378    }
379    buffer = 0;
380    bits = 0;
381
382}
383
384
385
386
387
388
389
390
391int yyerror(char *s)
392{
393    element_t *tmp;
394   
395    fprintf(stderr, "XXX %s\n"
396                    "XXX %s on line %d\n"
397                    "XXX Falling back to generic_decode()\n",
398                    file, s, lines);
399    /*
400     * Clear the list so we don't do partial matching...makes it a bit
401     * more obvious that something is broken perhaps.
402     * XXX Not sure if it is better to parse none of the packet, or part
403     * of the packet in the event of error? Feel free to remove this if
404     * that is desired.
405     */
406
407    while(el_list != NULL)
408    {
409        tmp = el_list;
410        el_list = el_list->next;
411
412        switch(tmp->type)
413        {
414            case FIELD: free(tmp->data->field); break;
415            case NEXTHEADER: free(tmp->data->nextheader); break;
416        }
417        free(tmp->data);       
418        free(tmp);
419        printf("deleting...\n");
420    }
421
422    return 0;
423}
424
425/*
426 * Could be shortcut with a pointer to the tail...
427 */
428element_t* append(element_t *list, element_t *item)
429{
430    if(list == NULL)
431        return item;
432
433    list->next = append(list->next, item);
434    return list;
435}
436/*
437 * Testing...
438 */
439void print_list(element_t *list)
440{
441    if(list == NULL)
442        return;
443       
444    switch(list->type)
445    {
446        case NEXTHEADER: printf("*Nextheader, prefix='%s', target='%s'\n",
447                            list->data->nextheader->prefix,
448                            list->data->nextheader->fieldname);
449                            break;
450       
451        case FIELD: printf("*Field, order = '%d', size = '%d', "
452                            "display='%d', name='%s'\n",
453                            list->data->field->order,
454                            list->data->field->size,
455                            list->data->field->display,
456                            list->data->field->identifier);
457                            break;
458    };
459    /*printf("%s\n", list->data->identifier); */
460    print_list(list->next);
461}
Note: See TracBrowser for help on using the repository browser.