source: libpacketdump/bitbuffer.c @ e224862

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since e224862 was fade02b, checked in by Shane Alcock <salcock@…>, 11 years ago
  • Fix strict-aliasing warning in bitbuffer.c
  • Fixed warnings about unused functions in the lexer code
  • Property mode set to 100644
File size: 7.7 KB
Line 
1#include "bitbuffer.h"
2#include <inttypes.h>
3#include "parser.h"
4#include <stdio.h>
5#include <netinet/in.h>
6#include <assert.h>
7#include <stdlib.h>
8#include <arpa/inet.h>
9#include "libpacketdump.h"
10
11uint16_t bits;
12/* "the largest possible type the compiler supports" */
13bitbuffer_t buffer;
14
15static bitbuffer_t getbit(void **packet, int *packlen, uint64_t numbits)
16{
17    bitbuffer_t ret;
18    bitbuffer_t mask;
19   
20    char *pktptr = NULL;
21
22    /* While the buffer is not filled up and there is still
23     * data in the packet to read, read a byte...
24     *
25     * The buffer gets filled from right to left
26     */
27    while(bits < numbits && *packlen > 0)
28    {
29        uint8_t byte;
30        /* read in one byte from the packet */
31        byte=(*((bitbuffer_t*)*packet))&0xff;
32        buffer |= (bitbuffer_t)byte << (sizeof(bitbuffer_t)*8-(bits+sizeof(byte)*8));
33        /* update the position within the packet */
34        pktptr = (char *)*packet;
35        pktptr += 1;
36        *packet = pktptr;
37
38        //*packet = ((char*)*packet) + 1;
39
40        bits += sizeof(byte)*8;
41        *packlen -= 1;
42    }
43
44    /* our return value is the first <numbits> of the buffer */
45    mask = ~((1ULL<<((sizeof(bitbuffer_t)*8-numbits)))-1);
46    ret = buffer & mask;
47    ret >>=(sizeof(bitbuffer_t)*8-numbits);
48   
49    /* remove the bits that are being returned from out buffer */
50    buffer <<= numbits;
51
52    /* and update our position inside this buffer */
53    bits -= numbits;
54
55    return ret;
56}
57
58int yyparse(void);
59
60element_t* parse_protocol_file(char *filename)
61{
62    /* hold onto this so we can put it in any error messages */
63    file = filename;
64
65    /* if the protocol file doesn't exist, we return null and
66     * it will fall back to using the generic_decode function
67     */
68    yyin = fopen(filename, "r");
69    if(!yyin)
70        return NULL;
71
72    el_list = NULL;
73    lines = 1;
74
75    yyparse();
76    fclose(yyin);
77    return el_list;
78}
79
80
81static bitbuffer_t fix_byteorder(bitbuffer_t value,
82                enum byte_order_t order, uint64_t size)
83{
84    bitbuffer_t one = 1;
85    bitbuffer_t lhs;
86    bitbuffer_t rhs;;
87
88    /*
89     * XXX trial and error seems to show these numbers to work.
90     * I've tried fields of length 1,2,3,4,8,13,16,32 and they seem to work.
91     * Others are untested...
92     */
93    switch(order)
94    {
95        case BIGENDIAN:
96            if(size < 16)
97                return value;
98            if(size < 32)
99                return ntohs(value);
100            if(size <= 32)
101                return ntohl(value);
102           
103            lhs = ntohl(value& ((one<<32)-1));
104            rhs = ntohl(value >> 32);
105            return ((lhs<<32) | rhs);
106
107        case LITTLEENDIAN:
108            return value;
109
110    };
111
112    /* should never get here */
113    assert(0);
114    return 0;
115}
116
117
118
119void decode_protocol_file(uint16_t link_type UNUSED,const char *packet,int len,element_t *el)
120{
121    bitbuffer_t result;
122
123    while(el != NULL)
124    {
125        switch(el->type)
126        {
127            case FIELD:
128                if (len*8+bits<el->data->field->size) {
129                        printf(" [Truncated]\n");
130                        return;
131                }
132                result = getbit((void*)&packet, &len, el->data->field->size); 
133
134                switch(el->data->field->display)
135                {
136                    /* integers get byteswapped if needed and displayed */
137                    case DISPLAY_INT:
138                    {
139                        result = fix_byteorder(result, 
140                                el->data->field->order, 
141                                el->data->field->size);
142                               
143                        el->data->field->value = result;
144                        printf(" %s %" PRIi64 "\n", 
145                                el->data->field->identifier,
146                                result);
147                    }
148                    break;
149
150                    /*
151                     * hex numbers get byteswapped if needed and displayed
152                     * without being padded with zeroes
153                     */
154                    case DISPLAY_HEX:
155                    { 
156                        result = fix_byteorder(result, 
157                                el->data->field->order, 
158                                el->data->field->size);
159                       
160                        el->data->field->value = result;
161                        printf(" %s 0x%" PRIx64 "\n", 
162                                el->data->field->identifier,
163                                result);
164                    }
165                    break;
166                   
167                    /*
168                     * ipv4 addresses stay in network byte order and are
169                     * given to inet_ntoa() to deal with
170                     */
171                    case DISPLAY_IPV4:
172                    {
173                        /* assumes all ipv4 addresses are 32bit fields */
174                        struct in_addr address;
175                        address.s_addr = (uint32_t)result;
176                        el->data->field->value = result;
177                   
178                        printf(" %s %s\n", 
179                                el->data->field->identifier,
180                                inet_ntoa(address));
181                    }
182                    break;
183
184                    /*
185                     * mac addresses stay in network byte order and are
186                     * displayed byte by byte with zero padding
187                     */
188                    case DISPLAY_MAC:
189                    {
190                        /* assumes all mac addresses are 48bit fields */
191                        uint8_t *ptr = (uint8_t*)&result;
192                        el->data->field->value = result;
193                        printf(" %s %02x:%02x:%02x:%02x:%02x:%02x\n",
194                                el->data->field->identifier,
195                                ptr[0], ptr[1], ptr[2], 
196                                ptr[3], ptr[4], ptr[5]);
197                    }
198                    break;
199                   
200                    /*
201                     * Flag values are only displayed if their value is true
202                     * otherwise they are ignored
203                     */
204                    case DISPLAY_FLAG:
205                    {
206                        el->data->field->value = result;
207                        if(result)
208                            printf(" %s\n", el->data->field->identifier);
209                    }
210                    break;
211
212                    /*
213                     * Hidden values are not displayed at all. This is useful
214                     * for reserved fields or information that you don't care
215                     * about but need to read in order to get to the rest of
216                     * the header
217                     */
218                    case DISPLAY_NONE:
219                    {
220                        result = fix_byteorder(result, 
221                                el->data->field->order, 
222                                el->data->field->size);
223                        el->data->field->value = result;
224                    }
225                    break;
226                };
227
228                break;
229
230            case NEXTHEADER:
231                /*
232                 * Before we move on to the next header, make sure our packet
233                 * pointer is pointing to the first unused bytes. This may
234                 * mean we have to backtrack to some that were put into the
235                 * buffer but weren't used.
236                 * - This wouldn't be a problem if all future output came
237                 * from this buffer, but there is a good chance we will use
238                 * some code from a shared library to output packet info
239                 * instead, and this doesn't have access to the buffer.
240                 */
241                packet = packet - (bits / 8);
242                len = len + (bits / 8);
243                bits = 0;
244                buffer = 0;
245
246                decode_next(packet, len, el->data->nextheader->prefix, 
247                        ntohs(el->data->nextheader->target->value));
248                break;
249        };
250       
251        el = el->next;
252    }
253    buffer = 0;
254    bits = 0;
255
256}
257
258
259
260
261
262
263
264
265int yyerror(char *s)
266{
267    element_t *tmp;
268   
269    fprintf(stderr, "XXX %s\n"
270                    "XXX %s on line %d\n"
271                    "XXX Falling back to generic_decode()\n", 
272                    file, s, lines);
273    /*
274     * Clear the list so we don't do partial matching...makes it a bit
275     * more obvious that something is broken perhaps.
276     * XXX Not sure if it is better to parse none of the packet, or part
277     * of the packet in the event of error? Feel free to remove this if
278     * that is desired.
279     */
280
281    while(el_list != NULL)
282    {
283        tmp = el_list;
284        el_list = el_list->next;
285
286        switch(tmp->type)
287        {
288            case FIELD: free(tmp->data->field); break;
289            case NEXTHEADER: free(tmp->data->nextheader); break;
290        }
291        free(tmp->data);       
292        free(tmp);
293        printf("deleting...\n");
294    }
295
296    return 0;
297}
298
299/*
300 * Could be shortcut with a pointer to the tail...
301 */
302element_t* append(element_t *list, element_t *item)
303{
304    if(list == NULL)
305        return item;
306
307    list->next = append(list->next, item);
308    return list;
309}
310/*
311 * Testing...
312 */
313void print_list(element_t *list)
314{
315    if(list == NULL)
316        return;
317       
318    switch(list->type)
319    {
320        case NEXTHEADER: printf("*Nextheader, prefix='%s', target='%s'\n", 
321                            list->data->nextheader->prefix, 
322                            list->data->nextheader->fieldname);
323                            break;
324       
325        case FIELD: printf("*Field, order = '%d', size = '%d', "
326                            "display='%d', name='%s'\n",
327                            list->data->field->order, 
328                            list->data->field->size, 
329                            list->data->field->display,
330                            list->data->field->identifier);
331                            break;
332    };
333    /*printf("%s\n", list->data->identifier); */
334    print_list(list->next);
335}
336#ifdef TEST
337#include <stdio.h>
338int main(void)
339{
340        unsigned char mybuffer[] = { 0x01, 0x82, 0x03, 0x04, 0x05, 0x06 };
341        void *buf = mybuffer;
342        int len=sizeof(buffer);
343        printf("8bits=%"PRIx64"\n",getbit(&buf,&len,8));
344        printf("2bits=%"PRIx64"\n",getbit(&buf,&len,2));
345        return 0;
346}
347#endif
Note: See TracBrowser for help on using the repository browser.