source: libpacketdump/parser/parser.y @ 41ab052

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

Fix bitordering issues

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