source: lib/protocols_l2.c @ 979a84f4

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 979a84f4 was 979a84f4, checked in by Shane Alcock <salcock@…>, 10 years ago
  • We now cache the wire length as well
  • If we're going to cache the link type, we should probably use it whenever we call trace_get_link_type()!
  • Property mode set to 100644
File size: 16.3 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)->l2_header = meta;
384                        ((libtrace_packet_t*)packet)->l2_remaining = *remaining;
385                        return meta;
386                case TRACE_TYPE_LINUX_SLL:
387                case TRACE_TYPE_80211_RADIO:
388                case TRACE_TYPE_80211_PRISM:
389                case TRACE_TYPE_PFLOG:
390                        break;
391        }
392
393        /* If there are meta-data headers, we need to skip over them until we
394         * find a non-meta data header and return that.
395         */
396        for(;;) {
397                void *nexthdr = trace_get_payload_from_meta(meta, 
398                                linktype, remaining);
399               
400                if (nexthdr == NULL) {
401                        switch (*linktype) {
402                                /* meta points to a layer 2 header! */
403                                case TRACE_TYPE_HDLC_POS:
404                                case TRACE_TYPE_ETH:
405                                case TRACE_TYPE_ATM:
406                                case TRACE_TYPE_80211:
407                                case TRACE_TYPE_NONE:
408                                case TRACE_TYPE_POS:
409                                case TRACE_TYPE_AAL5:
410                                case TRACE_TYPE_DUCK:
411                                case TRACE_TYPE_LLCSNAP:
412                                case TRACE_TYPE_PPP:
413                                case TRACE_TYPE_METADATA:
414                                case TRACE_TYPE_NONDATA:
415                                        ((libtrace_packet_t*)packet)->l2_header = meta;
416                                        ((libtrace_packet_t*)packet)->l2_remaining = *remaining;
417                                        return meta;
418                                case TRACE_TYPE_LINUX_SLL:
419                                case TRACE_TYPE_80211_RADIO:
420                                case TRACE_TYPE_80211_PRISM:
421                                case TRACE_TYPE_PFLOG:
422                                        break;
423                        }
424                       
425                        /* Otherwise, we must have hit the end of the packet */
426                        return NULL;
427                }
428         
429               
430                meta = nexthdr;
431        }
432
433}
434
435DLLEXPORT
436void *trace_get_payload_from_atm(void *link,
437                uint8_t *type, uint32_t *remaining)
438{
439        libtrace_atm_capture_cell_t *cell;
440        if (remaining && *remaining<sizeof(libtrace_atm_capture_cell_t)) {
441                *remaining = 0;
442                return NULL;
443        }
444        cell=(libtrace_atm_capture_cell_t*)link;
445
446        if (type)
447                *type=cell->pt;
448
449        if (remaining)
450                *remaining-=sizeof(libtrace_atm_capture_cell_t);
451
452        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
453}
454
455
456
457DLLEXPORT void *trace_get_payload_from_layer2(void *link,
458                libtrace_linktype_t linktype,
459                uint16_t *ethertype,
460                uint32_t *remaining)
461{
462        void *l;
463
464        if (linktype == ~0U) {
465                fprintf(stderr, "Unable to determine linktype for packet\n");
466                return NULL;
467        }
468       
469        switch(linktype) {
470                /* Packet Metadata headers, not layer2 headers */
471                case TRACE_TYPE_80211_PRISM:
472                case TRACE_TYPE_80211_RADIO:
473                case TRACE_TYPE_PFLOG:
474                case TRACE_TYPE_LINUX_SLL:
475                        return NULL;
476
477                /* duck packets have no payload! */
478                case TRACE_TYPE_DUCK:
479                        return NULL;
480
481                /* The payload is in these packets does
482                   not correspond to a genuine link-layer
483                   */
484                case TRACE_TYPE_METADATA:
485                case TRACE_TYPE_NONDATA:
486                        return NULL;
487
488                case TRACE_TYPE_80211:
489                        return trace_get_payload_from_80211(link,ethertype,remaining);
490                case TRACE_TYPE_ETH:
491                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
492                case TRACE_TYPE_NONE:
493                        if ((*(char*)link&0xF0) == 0x40)
494                                *ethertype=TRACE_ETHERTYPE_IP;   /* IPv4 */
495                        else if ((*(char*)link&0xF0) == 0x60)
496                                *ethertype=TRACE_ETHERTYPE_IPV6; /* IPv6 */
497                        return link; /* I love the simplicity */
498                case TRACE_TYPE_PPP:
499                        return trace_get_payload_from_ppp(link,ethertype,remaining);
500                case TRACE_TYPE_ATM:
501                        l=trace_get_payload_from_atm(link,NULL,remaining);
502                        /* FIXME: We shouldn't skip llcsnap here, we should
503                         * return an ethertype for it (somehow)
504                         */
505                        return (l ? trace_get_payload_from_llcsnap(l,
506                                                ethertype, remaining):NULL);
507                case TRACE_TYPE_LLCSNAP:
508                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
509
510                case TRACE_TYPE_HDLC_POS:
511                        return trace_get_payload_from_chdlc(link,ethertype,
512                                        remaining);
513                case TRACE_TYPE_POS:
514                        return trace_get_payload_from_ppp_hdlc(link,ethertype,
515                                        remaining);
516                /* TODO: Unsupported */
517                case TRACE_TYPE_AAL5:
518                        return NULL;
519        }
520        return NULL;
521
522}
523
524/* Take a pointer to the start of an IEEE 802.11 MAC frame and return a pointer
525 * to the source MAC address. 
526 * If the frame does not contain a sender address, e.g. ACK frame, return NULL.
527 * If the frame is a 4-address WDS frame, return TA, i.e. addr2.
528 * NB: This function decodes the 802.11 header, so it assumes that there are no
529 * bit-errors. If there are, all bets are off.
530 */
531static
532uint8_t *get_source_mac_from_wifi(void *wifi) {
533        struct libtrace_80211_t *w;
534        if (wifi == NULL) return NULL;
535        w = (struct libtrace_80211_t *) wifi;
536
537        /* If the frame is of type CTRL */
538        if (w->type == 0x1)
539                /* If bit 2 of the subtype field is zero, this indicates that
540                 * there is no transmitter address, i.e. the frame is either an
541                 * ACK or a CTS frame */
542                if ((w->subtype & 0x2) == 0)
543                        return NULL;
544
545        /* Always return the address of the transmitter, i.e. address 2 */
546        return (uint8_t *) &w->mac2;
547}
548
549DLLEXPORT uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
550        void *link;
551        uint32_t remaining;
552        libtrace_linktype_t linktype;
553        assert(packet);
554        link = trace_get_layer2(packet,&linktype,&remaining);
555
556        if (!link)
557                return NULL;
558
559        switch (linktype) {
560                case TRACE_TYPE_ETH:
561                        return (uint8_t *)&(((libtrace_ether_t*)link)->ether_shost);
562                case TRACE_TYPE_80211:
563                        return get_source_mac_from_wifi(link);
564                /* These packets don't have MAC addresses */
565                case TRACE_TYPE_POS:
566                case TRACE_TYPE_NONE:
567                case TRACE_TYPE_HDLC_POS:
568                case TRACE_TYPE_PFLOG:
569                case TRACE_TYPE_ATM:
570                case TRACE_TYPE_DUCK:
571                case TRACE_TYPE_METADATA:
572                case TRACE_TYPE_AAL5:
573                case TRACE_TYPE_LLCSNAP:
574                case TRACE_TYPE_PPP:
575                case TRACE_TYPE_NONDATA:
576                        return NULL;
577
578                /* Metadata headers should already be skipped */
579                case TRACE_TYPE_LINUX_SLL:
580                case TRACE_TYPE_80211_PRISM:
581                case TRACE_TYPE_80211_RADIO:
582                        assert(!"Metadata headers should already be skipped");
583                        break;
584        }
585        fprintf(stderr,"%s not implemented for linktype %i\n", __func__, linktype);
586        assert(0);
587        return NULL;
588}
589
590DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet)
591{
592        void *link;
593        libtrace_linktype_t linktype;
594        uint32_t remaining;
595        libtrace_80211_t *wifi;
596        libtrace_ether_t *ethptr;
597
598        link = trace_get_layer2(packet,&linktype,&remaining);
599
600        ethptr = (libtrace_ether_t*)link;
601
602
603        if (!link)
604                return NULL;
605
606        switch (linktype) {
607                case TRACE_TYPE_80211:
608                        wifi=(libtrace_80211_t*)link;
609                        return (uint8_t*)&wifi->mac1;
610                case TRACE_TYPE_ETH:
611                        return (uint8_t*)&ethptr->ether_dhost;
612                case TRACE_TYPE_POS:
613                case TRACE_TYPE_NONE:
614                case TRACE_TYPE_ATM:
615                case TRACE_TYPE_HDLC_POS:
616                case TRACE_TYPE_PFLOG:
617                case TRACE_TYPE_DUCK:
618                case TRACE_TYPE_METADATA:
619                case TRACE_TYPE_AAL5:
620                case TRACE_TYPE_LLCSNAP:
621                case TRACE_TYPE_PPP:   
622                case TRACE_TYPE_NONDATA:
623                        /* No MAC address */
624                        return NULL;
625                /* Metadata headers should already be skipped */
626                case TRACE_TYPE_LINUX_SLL:
627                case TRACE_TYPE_80211_PRISM:
628                case TRACE_TYPE_80211_RADIO:
629                        assert(!"Metadata headers should already be skipped");
630                        break;
631        }
632        fprintf(stderr,"Not implemented\n");
633        assert(0);
634        return NULL;
635}
636
Note: See TracBrowser for help on using the repository browser.