source: lib/protocols_l2.c @ 1326d5f

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 1326d5f was 1326d5f, checked in by Shane Alcock <salcock@…>, 11 years ago
  • OpenSolaris? also doesn't like it if you redefine FILE_OFFSET_BITS after it has defined it itself. The solution: make sure our definition occurs beforehand, e.g. moving config.h to the top of the include list
  • 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/* This file contains all the protocol decoding functions for layer 2
41 * (and 2.5) protocols. This includes functions for accessing MAC addresses.
42 *
43 * Supported protocols include (but are not limited to):
44 *      Ethernet
45 *      802.11
46 *      802.1q (vlan)
47 *      MPLS
48 *      PPPoE
49 *      LLCSnap
50 *      ATM
51 */
52
53
54/* Returns the payload from 802.3 ethernet.  Type optionally returned in
55 * "type" in host byte order.  This will return a vlan header.
56 */
57void *trace_get_payload_from_ethernet(void *ethernet, 
58                uint16_t *type,
59                uint32_t *remaining)
60{
61        libtrace_ether_t *eth = (libtrace_ether_t*)ethernet;
62
63        if (remaining) {
64                if (*remaining < sizeof(*eth)) {
65                        *remaining = 0;
66                        return NULL;
67                }
68                *remaining-=sizeof(*eth);
69        }
70
71        if (type)
72                *type = ntohs(eth->ether_type);
73
74        return (void*)((char *)eth + sizeof(*eth));
75}
76
77/* Skip any 802.1q headers if necessary
78 * type is now output only (why check it if we don't need to?)
79 */
80void *trace_get_payload_from_vlan(void *ethernet, uint16_t *type,
81                uint32_t *remaining)
82{
83        libtrace_8021q_t *vlanhdr = (libtrace_8021q_t *)ethernet;
84
85        if (remaining) {
86                if (*remaining < sizeof(libtrace_8021q_t)) {
87                        *remaining = 0;
88                        return NULL;
89                }
90
91                *remaining=*remaining-sizeof(libtrace_8021q_t);
92        }
93
94        if (type)
95                *type = ntohs(vlanhdr->vlan_ether_type);
96
97        return (void*)((char *)ethernet + sizeof(*vlanhdr));
98
99}
100
101/* Skip any MPLS headers if necessary, guessing what the next type is
102 * type is input/output.  If the next type is "ethernet" this will
103 * return a type of 0x0000.
104 */
105void *trace_get_payload_from_mpls(void *ethernet, uint16_t *type, 
106                uint32_t *remaining)
107{
108       
109        assert(type);
110        if ((((char*)ethernet)[2]&0x01)==0) {
111                /* The MPLS Stack bit is set */
112                *type = TRACE_ETHERTYPE_MPLS;
113        }
114        else {
115                if (!remaining || *remaining>=5) {
116                        switch (((char*)ethernet)[4]&0xF0) {
117                                case 0x40:      /* IPv4 */
118                                        *type = TRACE_ETHERTYPE_IP;
119                                        break;
120                                case 0x60:      /* IPv6 */
121                                        *type = TRACE_ETHERTYPE_IPV6;
122                                        break;
123                                default:        /* VPLS */
124                                        /* Ethernet */
125                                        *type = 0;
126                        }
127                }
128        }
129        ethernet=(char*)ethernet+4;
130        if (remaining) {
131                if (*remaining<4)
132                        return NULL;
133                else
134                        *remaining-=4;
135        }
136
137
138        return ethernet;
139}
140
141static void *trace_get_payload_from_llcsnap(void *link,
142                uint16_t *type, uint32_t *remaining)
143{
144        /* 64 byte capture. */
145        libtrace_llcsnap_t *llc = (libtrace_llcsnap_t*)link;
146
147        if (remaining) {
148                if (*remaining < sizeof(libtrace_llcsnap_t)) {
149                        *remaining = 0;
150                        return NULL;
151                }
152                *remaining-=(sizeof(libtrace_llcsnap_t));
153        }
154
155        llc = (libtrace_llcsnap_t*)((char *)llc);
156
157        if (type) *type = ntohs(llc->type);
158
159        return (void*)((char*)llc+sizeof(*llc));
160}
161
162
163static void *trace_get_payload_from_80211(void *link, uint16_t *type, uint32_t *remaining)
164{
165        libtrace_80211_t *wifi;
166        uint16_t *eth; /* ethertype */
167        int8_t extra = 0; /* how many QoS bytes to skip */
168       
169        if (remaining && *remaining < sizeof(libtrace_80211_t)) {
170                *remaining = 0;
171                return NULL;
172        }
173
174        wifi=(libtrace_80211_t*)link;
175
176        /* Data packet? */
177        if (wifi->type != 2) {
178                return NULL;
179        }
180
181        /* If FromDS and ToDS are both set then we have a four-address
182         * frame. Otherwise we have a three-address frame */
183        if (!(wifi->to_ds && wifi->from_ds)) 
184                extra -= 6; 
185       
186        /* Indicates QoS field present, see IEEE802.11e-2005 pg 21 */
187        if (wifi->subtype & 0x8) 
188                extra += 2;
189
190        if (remaining && *remaining < sizeof(*eth)) {
191                *remaining = 0;
192                return NULL;
193        }
194
195        eth=(uint16_t *)((char*)wifi+sizeof(*wifi)+extra);
196       
197        if (*eth == 0xaaaa)
198                /* Payload contains an 802.2 LLC/SNAP frame */
199                return trace_get_payload_from_llcsnap((void *)eth, type, remaining);
200                       
201        /* Otherwise we assume an Ethernet II frame */
202        if (type) *type=ntohs(*eth);
203        if (remaining) *remaining = *remaining - sizeof(libtrace_80211_t) - extra - sizeof(*eth);
204       
205        return (void*)((char*)eth+sizeof(*eth));
206}
207
208static void *trace_get_payload_from_ppp(void *link, 
209                uint16_t *type, uint32_t *remaining)
210{
211        /* 64 byte capture. */
212        libtrace_ppp_t *ppp = (libtrace_ppp_t*)link;
213
214        if (remaining) {
215                if (*remaining < sizeof(libtrace_ppp_t)) {
216                        *remaining = 0;
217                        return NULL;
218                }
219                *remaining-=sizeof(libtrace_ppp_t);
220        }
221
222        if (type) {
223                switch(ntohs(ppp->protocol)) {
224                        case 0x0021: *type = TRACE_ETHERTYPE_IP; break;
225                        /* If it isn't IP, then it is probably PPP control and
226                         * I can't imagine anyone caring about that too much
227                         */
228                        default: *type = 0; break;
229                }
230        }
231
232
233        return (void*)((char *)ppp+sizeof(*ppp));
234}
235
236void *trace_get_payload_from_pppoe(void *link, uint16_t *type, 
237                uint32_t *remaining) {
238        assert(type);
239       
240        if (remaining) {
241                if (*remaining < sizeof(libtrace_pppoe_t)) {
242                        *remaining = 0;
243                        return NULL;
244                }
245                *remaining -= sizeof(libtrace_pppoe_t);
246        }
247       
248        /* PPPoE is always followed by PPP */
249        return trace_get_payload_from_ppp(link + sizeof(libtrace_pppoe_t),
250                        type, remaining);
251}
252       
253/* Header for CHDLC framing */
254typedef struct libtrace_chdlc_t {
255        uint8_t address;        /** 0xF0 for unicast, 0xF8 for multicast */
256        uint8_t control;        /** Always 0x00 */
257        uint16_t ethertype;
258} libtrace_chdlc_t;
259
260/* Header for PPP in HDLC-like framing */
261typedef struct libtrace_ppp_hdlc_t {
262        uint8_t address;        /** Always should be 0xff */
263        uint8_t control;        /** Always should be 0x03 */
264        uint16_t protocol;     
265} libtrace_ppp_hdlc_t;
266
267static void *trace_get_payload_from_chdlc(void *link, uint16_t *type,
268                uint32_t *remaining) {
269
270        libtrace_chdlc_t *chdlc = (libtrace_chdlc_t *)link;
271
272        if (remaining) {
273                if (*remaining < sizeof(libtrace_chdlc_t)) {
274                        *remaining = 0;
275                        return NULL;
276                }
277                *remaining -= sizeof(libtrace_chdlc_t);
278        }
279
280        if (type) {
281                *type = ntohs(chdlc->ethertype);
282        }
283
284        return (void *)((char *)chdlc + sizeof(*chdlc));
285
286}
287
288static void *trace_get_payload_from_ppp_hdlc(void *link, 
289                uint16_t *type, uint32_t *remaining)
290{
291        libtrace_ppp_hdlc_t *ppp_hdlc = (libtrace_ppp_hdlc_t*)link;
292
293        if (remaining) {
294                if (*remaining < sizeof(libtrace_ppp_hdlc_t)) {
295                        *remaining = 0;
296                        return NULL;
297                }
298                *remaining-=sizeof(libtrace_ppp_hdlc_t);
299        }
300
301        if (type) {
302                /* http://www.iana.org/assignments/ppp-numbers */
303
304                switch(ntohs(ppp_hdlc->protocol)) {
305                        case 0x0021: /* IP */
306                                *type = TRACE_ETHERTYPE_IP;
307                                break;
308                        case 0xc021: /* Link Control Protocol */
309                                *type = 0; /* No ethertype for this */
310                                break;
311
312                        default:
313                                printf("Unknown chdlc type: %04x\n",
314                                                ntohs(ppp_hdlc->protocol));
315                                *type = 0; /* Unknown */
316                }
317        }
318
319
320        return (void*)((char *)ppp_hdlc+sizeof(*ppp_hdlc));
321}
322
323void *trace_get_payload_from_link(void *link, libtrace_linktype_t linktype, 
324                uint16_t *ethertype, uint32_t *remaining)
325{
326        void *l = NULL;
327
328        do {
329                l = trace_get_payload_from_meta(link, &linktype, remaining);
330                if (l != NULL) {
331                        link=l;
332                }
333        } while (l != NULL);
334
335        return trace_get_payload_from_layer2(link,linktype,ethertype,remaining);
336       
337}
338
339DLLEXPORT void *trace_get_layer2(const libtrace_packet_t *packet,
340                libtrace_linktype_t *linktype,
341                uint32_t *remaining) 
342{
343        uint32_t dummyrem;
344        void *meta = NULL;
345       
346        assert(packet != NULL);
347        assert(linktype != NULL);
348
349        if (remaining == NULL)
350                remaining = &dummyrem;
351       
352        meta = trace_get_packet_meta(packet, linktype, remaining);
353
354        /* If there are no meta-data headers, we just return the start of the
355         * packet buffer, along with the linktype, etc.
356         */
357        if (meta == NULL) 
358                return trace_get_packet_buffer(packet, linktype, remaining);
359       
360        /* If there are meta-data headers, we need to skip over them until we
361         * find a non-meta data header and return that.
362         */
363        for(;;) {
364                void *nexthdr = trace_get_payload_from_meta(meta, 
365                                linktype, remaining);
366                if (nexthdr == NULL)
367                        return meta;
368                meta = nexthdr;
369        }
370}
371
372DLLEXPORT
373void *trace_get_payload_from_atm(void *link,
374                uint8_t *type, uint32_t *remaining)
375{
376        libtrace_atm_capture_cell_t *cell;
377        if (remaining && *remaining<sizeof(libtrace_atm_capture_cell_t)) {
378                *remaining = 0;
379                return NULL;
380        }
381        cell=(libtrace_atm_capture_cell_t*)link;
382
383        if (type)
384                *type=cell->pt;
385
386        if (remaining)
387                *remaining-=sizeof(libtrace_atm_capture_cell_t);
388
389        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
390}
391
392
393
394DLLEXPORT void *trace_get_payload_from_layer2(void *link,
395                libtrace_linktype_t linktype,
396                uint16_t *ethertype,
397                uint32_t *remaining)
398{
399        void *l;
400        if (linktype == ~0U) {
401                fprintf(stderr, "Unable to determine linktype for packet\n");
402                return NULL;
403        }
404       
405        switch(linktype) {
406                /* Packet Metadata headers, not layer2 headers */
407                case TRACE_TYPE_80211_PRISM:
408                case TRACE_TYPE_80211_RADIO:
409                case TRACE_TYPE_PFLOG:
410                case TRACE_TYPE_LINUX_SLL:
411                        return NULL;
412
413                /* duck packets have no payload! */
414                case TRACE_TYPE_DUCK:
415                        return NULL;
416
417                /* The payload is in these packets does
418                   not correspond to a genuine link-layer
419                   */
420                case TRACE_TYPE_METADATA:
421                case TRACE_TYPE_NONDATA:
422                        return NULL;
423
424                case TRACE_TYPE_80211:
425                        return trace_get_payload_from_80211(link,ethertype,remaining);
426                case TRACE_TYPE_ETH:
427                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
428                case TRACE_TYPE_NONE:
429                        if ((*(char*)link&0xF0) == 0x40)
430                                *ethertype=TRACE_ETHERTYPE_IP;   /* IPv4 */
431                        else if ((*(char*)link&0xF0) == 0x60)
432                                *ethertype=TRACE_ETHERTYPE_IPV6; /* IPv6 */
433                        return link; /* I love the simplicity */
434                case TRACE_TYPE_PPP:
435                        return trace_get_payload_from_ppp(link,ethertype,remaining);
436                case TRACE_TYPE_ATM:
437                        l=trace_get_payload_from_atm(link,NULL,remaining);
438                        /* FIXME: We shouldn't skip llcsnap here, we should
439                         * return an ethertype for it (somehow)
440                         */
441                        return (l ? trace_get_payload_from_llcsnap(l,
442                                                ethertype, remaining):NULL);
443                case TRACE_TYPE_LLCSNAP:
444                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
445
446                case TRACE_TYPE_HDLC_POS:
447                        return trace_get_payload_from_chdlc(link,ethertype,
448                                        remaining);
449                case TRACE_TYPE_POS:
450                        return trace_get_payload_from_ppp_hdlc(link,ethertype,
451                                        remaining);
452                /* TODO: Unsupported */
453                case TRACE_TYPE_AAL5:
454                        return NULL;
455        }
456        return NULL;
457
458}
459
460/* Take a pointer to the start of an IEEE 802.11 MAC frame and return a pointer
461 * to the source MAC address. 
462 * If the frame does not contain a sender address, e.g. ACK frame, return NULL.
463 * If the frame is a 4-address WDS frame, return TA, i.e. addr2.
464 * NB: This function decodes the 802.11 header, so it assumes that there are no
465 * bit-errors. If there are, all bets are off.
466 */
467static
468uint8_t *get_source_mac_from_wifi(void *wifi) {
469        struct libtrace_80211_t *w;
470        if (wifi == NULL) return NULL;
471        w = (struct libtrace_80211_t *) wifi;
472
473        /* If the frame is of type CTRL */
474        if (w->type == 0x1)
475                /* If bit 2 of the subtype field is zero, this indicates that
476                 * there is no transmitter address, i.e. the frame is either an
477                 * ACK or a CTS frame */
478                if ((w->subtype & 0x2) == 0)
479                        return NULL;
480
481        /* Always return the address of the transmitter, i.e. address 2 */
482        return (uint8_t *) &w->mac2;
483}
484
485DLLEXPORT uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
486        void *link;
487        uint32_t remaining;
488        libtrace_linktype_t linktype;
489        assert(packet);
490        link = trace_get_layer2(packet,&linktype,&remaining);
491
492        if (!link)
493                return NULL;
494
495        switch (linktype) {
496                case TRACE_TYPE_ETH:
497                        return (uint8_t *)&(((libtrace_ether_t*)link)->ether_shost);
498                case TRACE_TYPE_80211:
499                        return get_source_mac_from_wifi(link);
500                /* These packets don't have MAC addresses */
501                case TRACE_TYPE_POS:
502                case TRACE_TYPE_NONE:
503                case TRACE_TYPE_HDLC_POS:
504                case TRACE_TYPE_PFLOG:
505                case TRACE_TYPE_ATM:
506                case TRACE_TYPE_DUCK:
507                case TRACE_TYPE_METADATA:
508                case TRACE_TYPE_AAL5:
509                case TRACE_TYPE_LLCSNAP:
510                case TRACE_TYPE_PPP:
511                case TRACE_TYPE_NONDATA:
512                        return NULL;
513
514                /* Metadata headers should already be skipped */
515                case TRACE_TYPE_LINUX_SLL:
516                case TRACE_TYPE_80211_PRISM:
517                case TRACE_TYPE_80211_RADIO:
518                        assert(!"Metadata headers should already be skipped");
519                        break;
520        }
521        fprintf(stderr,"%s not implemented for linktype %i\n", __func__, linktype);
522        assert(0);
523        return NULL;
524}
525
526DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet)
527{
528        void *link;
529        libtrace_linktype_t linktype;
530        uint32_t remaining;
531        libtrace_80211_t *wifi;
532        libtrace_ether_t *ethptr;
533
534        link = trace_get_layer2(packet,&linktype,&remaining);
535
536        ethptr = (libtrace_ether_t*)link;
537
538
539        if (!link)
540                return NULL;
541
542        switch (linktype) {
543                case TRACE_TYPE_80211:
544                        wifi=(libtrace_80211_t*)link;
545                        return (uint8_t*)&wifi->mac1;
546                case TRACE_TYPE_ETH:
547                        return (uint8_t*)&ethptr->ether_dhost;
548                case TRACE_TYPE_POS:
549                case TRACE_TYPE_NONE:
550                case TRACE_TYPE_ATM:
551                case TRACE_TYPE_HDLC_POS:
552                case TRACE_TYPE_PFLOG:
553                case TRACE_TYPE_DUCK:
554                case TRACE_TYPE_METADATA:
555                case TRACE_TYPE_AAL5:
556                case TRACE_TYPE_LLCSNAP:
557                case TRACE_TYPE_PPP:   
558                case TRACE_TYPE_NONDATA:
559                        /* No MAC address */
560                        return NULL;
561                /* Metadata headers should already be skipped */
562                case TRACE_TYPE_LINUX_SLL:
563                case TRACE_TYPE_80211_PRISM:
564                case TRACE_TYPE_80211_RADIO:
565                        assert(!"Metadata headers should already be skipped");
566                        break;
567        }
568        fprintf(stderr,"Not implemented\n");
569        assert(0);
570        return NULL;
571}
572
Note: See TracBrowser for help on using the repository browser.