source: lib/protocols_l2.c @ ee58d0d

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since ee58d0d was ee58d0d, checked in by Shane Alcock <salcock@…>, 10 years ago
  • Improved performance by caching more stuff, especially L2 headers and various "remaining" values - not much point caching something if you need to re-read the entire packet to calculate "remaining" still :)
  • Also improved performance of trace_get_layer2 by avoiding an effective double call of trace_get_packet_buffer
  • Fixed bug with payload length calculation if the packet has extra padding beyond what the IP len states
  • Improved (hopefully) performance when reading ERF traces by avoiding updating the drops counter if the loss counter was zero (should save an ntohs at least)
  • Property mode set to 100644
File size: 16.4 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
30 * $Id$
31 *
32 */
33
34#include "libtrace_int.h"
35#include "libtrace.h"
36#include "protocols.h"
37#include <assert.h>
38#include <stdlib.h>
39
40
41/* This file contains all the protocol decoding functions for layer 2
42 * (and 2.5) protocols. This includes functions for accessing MAC addresses.
43 *
44 * Supported protocols include (but are not limited to):
45 *      Ethernet
46 *      802.11
47 *      802.1q (vlan)
48 *      MPLS
49 *      PPPoE
50 *      LLCSnap
51 *      ATM
52 */
53
54
55/* Returns the payload from 802.3 ethernet.  Type optionally returned in
56 * "type" in host byte order.  This will return a vlan header.
57 */
58void *trace_get_payload_from_ethernet(void *ethernet, 
59                uint16_t *type,
60                uint32_t *remaining)
61{
62        libtrace_ether_t *eth = (libtrace_ether_t*)ethernet;
63
64        if (remaining) {
65                if (*remaining < sizeof(*eth)) {
66                        *remaining = 0;
67                        return NULL;
68                }
69                *remaining-=sizeof(*eth);
70        }
71
72        if (type)
73                *type = ntohs(eth->ether_type);
74
75        return (void*)((char *)eth + sizeof(*eth));
76}
77
78/* Skip any 802.1q headers if necessary
79 * type is now output only (why check it if we don't need to?)
80 */
81void *trace_get_payload_from_vlan(void *ethernet, uint16_t *type,
82                uint32_t *remaining)
83{
84        libtrace_8021q_t *vlanhdr = (libtrace_8021q_t *)ethernet;
85
86        if (remaining) {
87                if (*remaining < sizeof(libtrace_8021q_t)) {
88                        *remaining = 0;
89                        return NULL;
90                }
91
92                *remaining=*remaining-sizeof(libtrace_8021q_t);
93        }
94
95        if (type)
96                *type = ntohs(vlanhdr->vlan_ether_type);
97
98        return (void*)((char *)ethernet + sizeof(*vlanhdr));
99
100}
101
102/* Skip any MPLS headers if necessary, guessing what the next type is
103 * type is input/output.  If the next type is "ethernet" this will
104 * return a type of 0x0000.
105 */
106void *trace_get_payload_from_mpls(void *ethernet, uint16_t *type, 
107                uint32_t *remaining)
108{
109       
110        assert(type);
111        if ((((char*)ethernet)[2]&0x01)==0) {
112                /* The MPLS Stack bit is set */
113                *type = TRACE_ETHERTYPE_MPLS;
114        }
115        else {
116                if (!remaining || *remaining>=5) {
117                        switch (((char*)ethernet)[4]&0xF0) {
118                                case 0x40:      /* IPv4 */
119                                        *type = TRACE_ETHERTYPE_IP;
120                                        break;
121                                case 0x60:      /* IPv6 */
122                                        *type = TRACE_ETHERTYPE_IPV6;
123                                        break;
124                                default:        /* VPLS */
125                                        /* Ethernet */
126                                        *type = 0;
127                        }
128                }
129        }
130        ethernet=(char*)ethernet+4;
131        if (remaining) {
132                if (*remaining<4)
133                        return NULL;
134                else
135                        *remaining-=4;
136        }
137
138
139        return ethernet;
140}
141
142static void *trace_get_payload_from_llcsnap(void *link,
143                uint16_t *type, uint32_t *remaining)
144{
145        /* 64 byte capture. */
146        libtrace_llcsnap_t *llc = (libtrace_llcsnap_t*)link;
147
148        if (remaining) {
149                if (*remaining < sizeof(libtrace_llcsnap_t)) {
150                        *remaining = 0;
151                        return NULL;
152                }
153                *remaining-=(sizeof(libtrace_llcsnap_t));
154        }
155
156        llc = (libtrace_llcsnap_t*)((char *)llc);
157
158        if (type) *type = ntohs(llc->type);
159
160        return (void*)((char*)llc+sizeof(*llc));
161}
162
163
164static void *trace_get_payload_from_80211(void *link, uint16_t *type, uint32_t *remaining)
165{
166        libtrace_80211_t *wifi;
167        uint16_t *eth; /* ethertype */
168        int8_t extra = 0; /* how many QoS bytes to skip */
169       
170        if (remaining && *remaining < sizeof(libtrace_80211_t)) {
171                *remaining = 0;
172                return NULL;
173        }
174
175        wifi=(libtrace_80211_t*)link;
176
177        /* Data packet? */
178        if (wifi->type != 2) {
179                return NULL;
180        }
181
182        /* If FromDS and ToDS are both set then we have a four-address
183         * frame. Otherwise we have a three-address frame */
184        if (!(wifi->to_ds && wifi->from_ds)) 
185                extra -= 6; 
186       
187        /* Indicates QoS field present, see IEEE802.11e-2005 pg 21 */
188        if (wifi->subtype & 0x8) 
189                extra += 2;
190
191        if (remaining && *remaining < sizeof(*eth)) {
192                *remaining = 0;
193                return NULL;
194        }
195
196        eth=(uint16_t *)((char*)wifi+sizeof(*wifi)+extra);
197       
198        if (*eth == 0xaaaa)
199                /* Payload contains an 802.2 LLC/SNAP frame */
200                return trace_get_payload_from_llcsnap((void *)eth, type, remaining);
201                       
202        /* Otherwise we assume an Ethernet II frame */
203        if (type) *type=ntohs(*eth);
204        if (remaining) *remaining = *remaining - sizeof(libtrace_80211_t) - extra - sizeof(*eth);
205       
206        return (void*)((char*)eth+sizeof(*eth));
207}
208
209static void *trace_get_payload_from_ppp(void *link, 
210                uint16_t *type, uint32_t *remaining)
211{
212        /* 64 byte capture. */
213        libtrace_ppp_t *ppp = (libtrace_ppp_t*)link;
214
215        if (remaining) {
216                if (*remaining < sizeof(libtrace_ppp_t)) {
217                        *remaining = 0;
218                        return NULL;
219                }
220                *remaining-=sizeof(libtrace_ppp_t);
221        }
222
223        if (type) {
224                switch(ntohs(ppp->protocol)) {
225                        case 0x0021: *type = TRACE_ETHERTYPE_IP; break;
226                        /* If it isn't IP, then it is probably PPP control and
227                         * I can't imagine anyone caring about that too much
228                         */
229                        default: *type = 0; break;
230                }
231        }
232
233
234        return (void*)((char *)ppp+sizeof(*ppp));
235}
236
237void *trace_get_payload_from_pppoe(void *link, uint16_t *type, 
238                uint32_t *remaining) {
239        assert(type);
240       
241        if (remaining) {
242                if (*remaining < sizeof(libtrace_pppoe_t)) {
243                        *remaining = 0;
244                        return NULL;
245                }
246                *remaining -= sizeof(libtrace_pppoe_t);
247        }
248       
249        /* PPPoE is always followed by PPP */
250        return trace_get_payload_from_ppp(link + sizeof(libtrace_pppoe_t),
251                        type, remaining);
252}
253       
254/* Header for CHDLC framing */
255typedef struct libtrace_chdlc_t {
256        uint8_t address;        /** 0xF0 for unicast, 0xF8 for multicast */
257        uint8_t control;        /** Always 0x00 */
258        uint16_t ethertype;
259} libtrace_chdlc_t;
260
261/* Header for PPP in HDLC-like framing */
262typedef struct libtrace_ppp_hdlc_t {
263        uint8_t address;        /** Always should be 0xff */
264        uint8_t control;        /** Always should be 0x03 */
265        uint16_t protocol;     
266} libtrace_ppp_hdlc_t;
267
268static void *trace_get_payload_from_chdlc(void *link, uint16_t *type,
269                uint32_t *remaining) {
270
271        libtrace_chdlc_t *chdlc = (libtrace_chdlc_t *)link;
272
273        if (remaining) {
274                if (*remaining < sizeof(libtrace_chdlc_t)) {
275                        *remaining = 0;
276                        return NULL;
277                }
278                *remaining -= sizeof(libtrace_chdlc_t);
279        }
280
281        if (type) {
282                *type = ntohs(chdlc->ethertype);
283        }
284
285        return (void *)((char *)chdlc + sizeof(*chdlc));
286
287}
288
289static void *trace_get_payload_from_ppp_hdlc(void *link, 
290                uint16_t *type, uint32_t *remaining)
291{
292        libtrace_ppp_hdlc_t *ppp_hdlc = (libtrace_ppp_hdlc_t*)link;
293
294        if (remaining) {
295                if (*remaining < sizeof(libtrace_ppp_hdlc_t)) {
296                        *remaining = 0;
297                        return NULL;
298                }
299                *remaining-=sizeof(libtrace_ppp_hdlc_t);
300        }
301
302        if (type) {
303                /* http://www.iana.org/assignments/ppp-numbers */
304
305                switch(ntohs(ppp_hdlc->protocol)) {
306                        case 0x0021: /* IP */
307                                *type = TRACE_ETHERTYPE_IP;
308                                break;
309                        case 0xc021: /* Link Control Protocol */
310                                *type = 0; /* No ethertype for this */
311                                break;
312
313                        default:
314                                printf("Unknown chdlc type: %04x\n",
315                                                ntohs(ppp_hdlc->protocol));
316                                *type = 0; /* Unknown */
317                }
318        }
319
320
321        return (void*)((char *)ppp_hdlc+sizeof(*ppp_hdlc));
322}
323
324void *trace_get_payload_from_link(void *link, libtrace_linktype_t linktype, 
325                uint16_t *ethertype, uint32_t *remaining)
326{
327        void *l = NULL;
328
329        do {
330                l = trace_get_payload_from_meta(link, &linktype, remaining);
331                if (l != NULL) {
332                        link=l;
333                }
334        } while (l != NULL);
335
336        return trace_get_payload_from_layer2(link,linktype,ethertype,remaining);
337       
338}
339
340DLLEXPORT void *trace_get_layer2(const libtrace_packet_t *packet,
341                libtrace_linktype_t *linktype,
342                uint32_t *remaining) 
343{
344        uint32_t dummyrem;
345        void *meta = NULL;
346       
347        assert(packet != NULL);
348        assert(linktype != NULL);
349
350        if (remaining == NULL)
351                remaining = &dummyrem;
352
353        if (packet->l2_header) {
354                /* Use cached values */
355                *linktype = packet->link_type;
356                *remaining = packet->l2_remaining;
357                return packet->l2_header;
358        }
359
360        /* Code looks a bit inefficient, but I'm actually trying to avoid
361         * calling trace_get_packet_buffer more than once like we used to.
362         */
363       
364        meta = trace_get_packet_buffer(packet, linktype, remaining);
365
366        /* If there are no meta-data headers, we just return the start of the
367         * packet buffer, along with the linktype, etc.
368         */
369        switch(*linktype) {
370                /* meta points to a layer 2 header! */
371                case TRACE_TYPE_HDLC_POS:
372                case TRACE_TYPE_ETH:
373                case TRACE_TYPE_ATM:
374                case TRACE_TYPE_80211:
375                case TRACE_TYPE_NONE:
376                case TRACE_TYPE_POS:
377                case TRACE_TYPE_AAL5:
378                case TRACE_TYPE_DUCK:
379                case TRACE_TYPE_LLCSNAP:
380                case TRACE_TYPE_PPP:
381                case TRACE_TYPE_METADATA:
382                case TRACE_TYPE_NONDATA:
383                        ((libtrace_packet_t*)packet)->link_type = *linktype;
384                        ((libtrace_packet_t*)packet)->l2_header = meta;
385                        ((libtrace_packet_t*)packet)->l2_remaining = *remaining;
386                        return meta;
387                case TRACE_TYPE_LINUX_SLL:
388                case TRACE_TYPE_80211_RADIO:
389                case TRACE_TYPE_80211_PRISM:
390                case TRACE_TYPE_PFLOG:
391                        break;
392        }
393
394        /* If there are meta-data headers, we need to skip over them until we
395         * find a non-meta data header and return that.
396         */
397        for(;;) {
398                void *nexthdr = trace_get_payload_from_meta(meta, 
399                                linktype, remaining);
400               
401                if (nexthdr == NULL) {
402                        switch (*linktype) {
403                                /* meta points to a layer 2 header! */
404                                case TRACE_TYPE_HDLC_POS:
405                                case TRACE_TYPE_ETH:
406                                case TRACE_TYPE_ATM:
407                                case TRACE_TYPE_80211:
408                                case TRACE_TYPE_NONE:
409                                case TRACE_TYPE_POS:
410                                case TRACE_TYPE_AAL5:
411                                case TRACE_TYPE_DUCK:
412                                case TRACE_TYPE_LLCSNAP:
413                                case TRACE_TYPE_PPP:
414                                case TRACE_TYPE_METADATA:
415                                case TRACE_TYPE_NONDATA:
416                                        ((libtrace_packet_t*)packet)->link_type = *linktype;
417                                        ((libtrace_packet_t*)packet)->l2_header = meta;
418                                        ((libtrace_packet_t*)packet)->l2_remaining = *remaining;
419                                        return meta;
420                                case TRACE_TYPE_LINUX_SLL:
421                                case TRACE_TYPE_80211_RADIO:
422                                case TRACE_TYPE_80211_PRISM:
423                                case TRACE_TYPE_PFLOG:
424                                        break;
425                        }
426                       
427                        /* Otherwise, we must have hit the end of the packet */
428                        return NULL;
429                }
430         
431               
432                meta = nexthdr;
433        }
434
435}
436
437DLLEXPORT
438void *trace_get_payload_from_atm(void *link,
439                uint8_t *type, uint32_t *remaining)
440{
441        libtrace_atm_capture_cell_t *cell;
442        if (remaining && *remaining<sizeof(libtrace_atm_capture_cell_t)) {
443                *remaining = 0;
444                return NULL;
445        }
446        cell=(libtrace_atm_capture_cell_t*)link;
447
448        if (type)
449                *type=cell->pt;
450
451        if (remaining)
452                *remaining-=sizeof(libtrace_atm_capture_cell_t);
453
454        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
455}
456
457
458
459DLLEXPORT void *trace_get_payload_from_layer2(void *link,
460                libtrace_linktype_t linktype,
461                uint16_t *ethertype,
462                uint32_t *remaining)
463{
464        void *l;
465
466        if (linktype == ~0U) {
467                fprintf(stderr, "Unable to determine linktype for packet\n");
468                return NULL;
469        }
470       
471        switch(linktype) {
472                /* Packet Metadata headers, not layer2 headers */
473                case TRACE_TYPE_80211_PRISM:
474                case TRACE_TYPE_80211_RADIO:
475                case TRACE_TYPE_PFLOG:
476                case TRACE_TYPE_LINUX_SLL:
477                        return NULL;
478
479                /* duck packets have no payload! */
480                case TRACE_TYPE_DUCK:
481                        return NULL;
482
483                /* The payload is in these packets does
484                   not correspond to a genuine link-layer
485                   */
486                case TRACE_TYPE_METADATA:
487                case TRACE_TYPE_NONDATA:
488                        return NULL;
489
490                case TRACE_TYPE_80211:
491                        return trace_get_payload_from_80211(link,ethertype,remaining);
492                case TRACE_TYPE_ETH:
493                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
494                case TRACE_TYPE_NONE:
495                        if ((*(char*)link&0xF0) == 0x40)
496                                *ethertype=TRACE_ETHERTYPE_IP;   /* IPv4 */
497                        else if ((*(char*)link&0xF0) == 0x60)
498                                *ethertype=TRACE_ETHERTYPE_IPV6; /* IPv6 */
499                        return link; /* I love the simplicity */
500                case TRACE_TYPE_PPP:
501                        return trace_get_payload_from_ppp(link,ethertype,remaining);
502                case TRACE_TYPE_ATM:
503                        l=trace_get_payload_from_atm(link,NULL,remaining);
504                        /* FIXME: We shouldn't skip llcsnap here, we should
505                         * return an ethertype for it (somehow)
506                         */
507                        return (l ? trace_get_payload_from_llcsnap(l,
508                                                ethertype, remaining):NULL);
509                case TRACE_TYPE_LLCSNAP:
510                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
511
512                case TRACE_TYPE_HDLC_POS:
513                        return trace_get_payload_from_chdlc(link,ethertype,
514                                        remaining);
515                case TRACE_TYPE_POS:
516                        return trace_get_payload_from_ppp_hdlc(link,ethertype,
517                                        remaining);
518                /* TODO: Unsupported */
519                case TRACE_TYPE_AAL5:
520                        return NULL;
521        }
522        return NULL;
523
524}
525
526/* Take a pointer to the start of an IEEE 802.11 MAC frame and return a pointer
527 * to the source MAC address. 
528 * If the frame does not contain a sender address, e.g. ACK frame, return NULL.
529 * If the frame is a 4-address WDS frame, return TA, i.e. addr2.
530 * NB: This function decodes the 802.11 header, so it assumes that there are no
531 * bit-errors. If there are, all bets are off.
532 */
533static
534uint8_t *get_source_mac_from_wifi(void *wifi) {
535        struct libtrace_80211_t *w;
536        if (wifi == NULL) return NULL;
537        w = (struct libtrace_80211_t *) wifi;
538
539        /* If the frame is of type CTRL */
540        if (w->type == 0x1)
541                /* If bit 2 of the subtype field is zero, this indicates that
542                 * there is no transmitter address, i.e. the frame is either an
543                 * ACK or a CTS frame */
544                if ((w->subtype & 0x2) == 0)
545                        return NULL;
546
547        /* Always return the address of the transmitter, i.e. address 2 */
548        return (uint8_t *) &w->mac2;
549}
550
551DLLEXPORT uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
552        void *link;
553        uint32_t remaining;
554        libtrace_linktype_t linktype;
555        assert(packet);
556        link = trace_get_layer2(packet,&linktype,&remaining);
557
558        if (!link)
559                return NULL;
560
561        switch (linktype) {
562                case TRACE_TYPE_ETH:
563                        return (uint8_t *)&(((libtrace_ether_t*)link)->ether_shost);
564                case TRACE_TYPE_80211:
565                        return get_source_mac_from_wifi(link);
566                /* These packets don't have MAC addresses */
567                case TRACE_TYPE_POS:
568                case TRACE_TYPE_NONE:
569                case TRACE_TYPE_HDLC_POS:
570                case TRACE_TYPE_PFLOG:
571                case TRACE_TYPE_ATM:
572                case TRACE_TYPE_DUCK:
573                case TRACE_TYPE_METADATA:
574                case TRACE_TYPE_AAL5:
575                case TRACE_TYPE_LLCSNAP:
576                case TRACE_TYPE_PPP:
577                case TRACE_TYPE_NONDATA:
578                        return NULL;
579
580                /* Metadata headers should already be skipped */
581                case TRACE_TYPE_LINUX_SLL:
582                case TRACE_TYPE_80211_PRISM:
583                case TRACE_TYPE_80211_RADIO:
584                        assert(!"Metadata headers should already be skipped");
585                        break;
586        }
587        fprintf(stderr,"%s not implemented for linktype %i\n", __func__, linktype);
588        assert(0);
589        return NULL;
590}
591
592DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet)
593{
594        void *link;
595        libtrace_linktype_t linktype;
596        uint32_t remaining;
597        libtrace_80211_t *wifi;
598        libtrace_ether_t *ethptr;
599
600        link = trace_get_layer2(packet,&linktype,&remaining);
601
602        ethptr = (libtrace_ether_t*)link;
603
604
605        if (!link)
606                return NULL;
607
608        switch (linktype) {
609                case TRACE_TYPE_80211:
610                        wifi=(libtrace_80211_t*)link;
611                        return (uint8_t*)&wifi->mac1;
612                case TRACE_TYPE_ETH:
613                        return (uint8_t*)&ethptr->ether_dhost;
614                case TRACE_TYPE_POS:
615                case TRACE_TYPE_NONE:
616                case TRACE_TYPE_ATM:
617                case TRACE_TYPE_HDLC_POS:
618                case TRACE_TYPE_PFLOG:
619                case TRACE_TYPE_DUCK:
620                case TRACE_TYPE_METADATA:
621                case TRACE_TYPE_AAL5:
622                case TRACE_TYPE_LLCSNAP:
623                case TRACE_TYPE_PPP:   
624                case TRACE_TYPE_NONDATA:
625                        /* No MAC address */
626                        return NULL;
627                /* Metadata headers should already be skipped */
628                case TRACE_TYPE_LINUX_SLL:
629                case TRACE_TYPE_80211_PRISM:
630                case TRACE_TYPE_80211_RADIO:
631                        assert(!"Metadata headers should already be skipped");
632                        break;
633        }
634        fprintf(stderr,"Not implemented\n");
635        assert(0);
636        return NULL;
637}
638
Note: See TracBrowser for help on using the repository browser.