source: lib/protocols_l2.c @ ac6ac7f

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since ac6ac7f was f7bcbfb, checked in by Shane Alcock <salcock@…>, 7 years ago

Fixed warnings that cropped up when building with clang

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