source: lib/protocols_l2.c @ 9cc1266

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 9cc1266 was 9cc1266, checked in by Shane Alcock <salcock@…>, 11 years ago
  • Fixed poor performance of the event API by greatly reducing the amount of packets created, copied and freed
  • We now cache the transport header and payload length for each packet
  • We now deal with Linux SLL Ethernet captures taken using tcpdump with -i any correctly.
  • Changed parameters for internal function trace_get_payload_from_sll - it now sets both the arphrd type and the next protocol
  • Moved ARPHRD definitions into a separate header file, as they come in handy anywhere we deal with SLL headers
  • Property mode set to 100644
File size: 14.8 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        meta = trace_get_packet_meta(packet, linktype, remaining);
354
355        /* If there are no meta-data headers, we just return the start of the
356         * packet buffer, along with the linktype, etc.
357         */
358        if (meta == NULL) 
359                return trace_get_packet_buffer(packet, linktype, remaining);
360       
361        /* If there are meta-data headers, we need to skip over them until we
362         * find a non-meta data header and return that.
363         */
364        for(;;) {
365                void *nexthdr = trace_get_payload_from_meta(meta, 
366                                linktype, remaining);
367                if (nexthdr == NULL)
368                        return meta;
369                meta = nexthdr;
370        }
371}
372
373DLLEXPORT
374void *trace_get_payload_from_atm(void *link,
375                uint8_t *type, uint32_t *remaining)
376{
377        libtrace_atm_capture_cell_t *cell;
378        if (remaining && *remaining<sizeof(libtrace_atm_capture_cell_t)) {
379                *remaining = 0;
380                return NULL;
381        }
382        cell=(libtrace_atm_capture_cell_t*)link;
383
384        if (type)
385                *type=cell->pt;
386
387        if (remaining)
388                *remaining-=sizeof(libtrace_atm_capture_cell_t);
389
390        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
391}
392
393
394
395DLLEXPORT void *trace_get_payload_from_layer2(void *link,
396                libtrace_linktype_t linktype,
397                uint16_t *ethertype,
398                uint32_t *remaining)
399{
400        void *l;
401
402        if (linktype == ~0U) {
403                fprintf(stderr, "Unable to determine linktype for packet\n");
404                return NULL;
405        }
406       
407        switch(linktype) {
408                /* Packet Metadata headers, not layer2 headers */
409                case TRACE_TYPE_80211_PRISM:
410                case TRACE_TYPE_80211_RADIO:
411                case TRACE_TYPE_PFLOG:
412                case TRACE_TYPE_LINUX_SLL:
413                        return NULL;
414
415                /* duck packets have no payload! */
416                case TRACE_TYPE_DUCK:
417                        return NULL;
418
419                /* The payload is in these packets does
420                   not correspond to a genuine link-layer
421                   */
422                case TRACE_TYPE_METADATA:
423                case TRACE_TYPE_NONDATA:
424                        return NULL;
425
426                case TRACE_TYPE_80211:
427                        return trace_get_payload_from_80211(link,ethertype,remaining);
428                case TRACE_TYPE_ETH:
429                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
430                case TRACE_TYPE_NONE:
431                        if ((*(char*)link&0xF0) == 0x40)
432                                *ethertype=TRACE_ETHERTYPE_IP;   /* IPv4 */
433                        else if ((*(char*)link&0xF0) == 0x60)
434                                *ethertype=TRACE_ETHERTYPE_IPV6; /* IPv6 */
435                        return link; /* I love the simplicity */
436                case TRACE_TYPE_PPP:
437                        return trace_get_payload_from_ppp(link,ethertype,remaining);
438                case TRACE_TYPE_ATM:
439                        l=trace_get_payload_from_atm(link,NULL,remaining);
440                        /* FIXME: We shouldn't skip llcsnap here, we should
441                         * return an ethertype for it (somehow)
442                         */
443                        return (l ? trace_get_payload_from_llcsnap(l,
444                                                ethertype, remaining):NULL);
445                case TRACE_TYPE_LLCSNAP:
446                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
447
448                case TRACE_TYPE_HDLC_POS:
449                        return trace_get_payload_from_chdlc(link,ethertype,
450                                        remaining);
451                case TRACE_TYPE_POS:
452                        return trace_get_payload_from_ppp_hdlc(link,ethertype,
453                                        remaining);
454                /* TODO: Unsupported */
455                case TRACE_TYPE_AAL5:
456                        return NULL;
457        }
458        return NULL;
459
460}
461
462/* Take a pointer to the start of an IEEE 802.11 MAC frame and return a pointer
463 * to the source MAC address. 
464 * If the frame does not contain a sender address, e.g. ACK frame, return NULL.
465 * If the frame is a 4-address WDS frame, return TA, i.e. addr2.
466 * NB: This function decodes the 802.11 header, so it assumes that there are no
467 * bit-errors. If there are, all bets are off.
468 */
469static
470uint8_t *get_source_mac_from_wifi(void *wifi) {
471        struct libtrace_80211_t *w;
472        if (wifi == NULL) return NULL;
473        w = (struct libtrace_80211_t *) wifi;
474
475        /* If the frame is of type CTRL */
476        if (w->type == 0x1)
477                /* If bit 2 of the subtype field is zero, this indicates that
478                 * there is no transmitter address, i.e. the frame is either an
479                 * ACK or a CTS frame */
480                if ((w->subtype & 0x2) == 0)
481                        return NULL;
482
483        /* Always return the address of the transmitter, i.e. address 2 */
484        return (uint8_t *) &w->mac2;
485}
486
487DLLEXPORT uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
488        void *link;
489        uint32_t remaining;
490        libtrace_linktype_t linktype;
491        assert(packet);
492        link = trace_get_layer2(packet,&linktype,&remaining);
493
494        if (!link)
495                return NULL;
496
497        switch (linktype) {
498                case TRACE_TYPE_ETH:
499                        return (uint8_t *)&(((libtrace_ether_t*)link)->ether_shost);
500                case TRACE_TYPE_80211:
501                        return get_source_mac_from_wifi(link);
502                /* These packets don't have MAC addresses */
503                case TRACE_TYPE_POS:
504                case TRACE_TYPE_NONE:
505                case TRACE_TYPE_HDLC_POS:
506                case TRACE_TYPE_PFLOG:
507                case TRACE_TYPE_ATM:
508                case TRACE_TYPE_DUCK:
509                case TRACE_TYPE_METADATA:
510                case TRACE_TYPE_AAL5:
511                case TRACE_TYPE_LLCSNAP:
512                case TRACE_TYPE_PPP:
513                case TRACE_TYPE_NONDATA:
514                        return NULL;
515
516                /* Metadata headers should already be skipped */
517                case TRACE_TYPE_LINUX_SLL:
518                case TRACE_TYPE_80211_PRISM:
519                case TRACE_TYPE_80211_RADIO:
520                        assert(!"Metadata headers should already be skipped");
521                        break;
522        }
523        fprintf(stderr,"%s not implemented for linktype %i\n", __func__, linktype);
524        assert(0);
525        return NULL;
526}
527
528DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet)
529{
530        void *link;
531        libtrace_linktype_t linktype;
532        uint32_t remaining;
533        libtrace_80211_t *wifi;
534        libtrace_ether_t *ethptr;
535
536        link = trace_get_layer2(packet,&linktype,&remaining);
537
538        ethptr = (libtrace_ether_t*)link;
539
540
541        if (!link)
542                return NULL;
543
544        switch (linktype) {
545                case TRACE_TYPE_80211:
546                        wifi=(libtrace_80211_t*)link;
547                        return (uint8_t*)&wifi->mac1;
548                case TRACE_TYPE_ETH:
549                        return (uint8_t*)&ethptr->ether_dhost;
550                case TRACE_TYPE_POS:
551                case TRACE_TYPE_NONE:
552                case TRACE_TYPE_ATM:
553                case TRACE_TYPE_HDLC_POS:
554                case TRACE_TYPE_PFLOG:
555                case TRACE_TYPE_DUCK:
556                case TRACE_TYPE_METADATA:
557                case TRACE_TYPE_AAL5:
558                case TRACE_TYPE_LLCSNAP:
559                case TRACE_TYPE_PPP:   
560                case TRACE_TYPE_NONDATA:
561                        /* No MAC address */
562                        return NULL;
563                /* Metadata headers should already be skipped */
564                case TRACE_TYPE_LINUX_SLL:
565                case TRACE_TYPE_80211_PRISM:
566                case TRACE_TYPE_80211_RADIO:
567                        assert(!"Metadata headers should already be skipped");
568                        break;
569        }
570        fprintf(stderr,"Not implemented\n");
571        assert(0);
572        return NULL;
573}
574
Note: See TracBrowser for help on using the repository browser.