source: libpacketdump/parser/parser.y @ 14b2010

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 14b2010 was 14b2010, checked in by Brendon Jones <brendonj@…>, 15 years ago

Parser to parse .protocol files for use with libpacketdump.

Hopefully it works.

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