source: lib/protocols_l2.c @ f6730d8

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since f6730d8 was f6730d8, checked in by Shane Alcock <salcock@…>, 12 years ago
  • Updated licensing and documentation for the protocol decoders
  • Moved trace_get_source_mac and trace_get_destination_mac into protocols_l2.c which is much more appropriate
  • Re-wrote trace_get_destination_mac to match the behaviour of trace_get_source_mac, especially with regard to ignoring link types that match meta-data headers
  • Added TRACE_TYPE_NONDATA handlers to several switch statements
  • Property mode set to 100644
File size: 14.0 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.h"
35#include "protocols.h"
36#include "libtrace_int.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
254typedef struct libtrace_chdlc_t {
255        uint8_t address;        /** 0xF0 for unicast, 0xF8 for multicast */
256        uint8_t control;
257        uint16_t ethertype;
258} libtrace_chdlc_t;
259
260static void *trace_get_payload_from_chdlc(void *link, 
261                uint16_t *type, uint32_t *remaining)
262{
263        libtrace_chdlc_t *chdlc = (libtrace_chdlc_t*)link;
264
265        if (remaining) {
266                if (*remaining < sizeof(libtrace_chdlc_t)) {
267                        *remaining = 0;
268                        return NULL;
269                }
270                *remaining-=sizeof(libtrace_chdlc_t);
271        }
272
273        if (type) {
274                switch(ntohs(chdlc->ethertype)) {
275                        case 0x0021: /* IP */
276                                *type = TRACE_ETHERTYPE_IP;
277                                break;
278                        case 0xc021: /* Link Control Protocol */
279                                *type = 0; /* No ethertype for this */
280                                break;
281
282                        default:
283                                printf("Unknown chdlc type: %04x\n",ntohs(chdlc->ethertype));
284                                *type = 0; /* Unknown */
285                }
286        }
287
288
289        return (void*)((char *)chdlc+sizeof(*chdlc));
290}
291
292void *trace_get_payload_from_link(void *link, libtrace_linktype_t linktype, 
293                uint16_t *ethertype, uint32_t *remaining)
294{
295        void *l = NULL;
296
297        do {
298                l = trace_get_payload_from_meta(link, &linktype, remaining);
299                if (l != NULL) {
300                        link=l;
301                }
302        } while (l != NULL);
303
304        return trace_get_payload_from_layer2(link,linktype,ethertype,remaining);
305       
306}
307
308DLLEXPORT void *trace_get_layer2(const libtrace_packet_t *packet,
309                libtrace_linktype_t *linktype,
310                uint32_t *remaining) 
311{
312        uint32_t dummyrem;
313        void *meta = NULL;
314       
315        assert(packet != NULL);
316        assert(linktype != NULL);
317
318        if (remaining == NULL)
319                remaining = &dummyrem;
320       
321        meta = trace_get_packet_meta(packet, linktype, remaining);
322
323        /* If there are no meta-data headers, we just return the start of the
324         * packet buffer, along with the linktype, etc.
325         */
326        if (meta == NULL) 
327                return trace_get_packet_buffer(packet, linktype, remaining);
328       
329        /* If there are meta-data headers, we need to skip over them until we
330         * find a non-meta data header and return that.
331         */
332        for(;;) {
333                void *nexthdr = trace_get_payload_from_meta(meta, 
334                                linktype, remaining);
335                if (nexthdr == NULL)
336                        return meta;
337                meta = nexthdr;
338        }
339}
340
341DLLEXPORT
342void *trace_get_payload_from_atm(void *link,
343                uint8_t *type, uint32_t *remaining)
344{
345        libtrace_atm_capture_cell_t *cell;
346        if (remaining && *remaining<sizeof(libtrace_atm_capture_cell_t)) {
347                *remaining = 0;
348                return NULL;
349        }
350        cell=(libtrace_atm_capture_cell_t*)link;
351
352        if (type)
353                *type=cell->pt;
354
355        if (remaining)
356                *remaining-=sizeof(libtrace_atm_capture_cell_t);
357
358        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
359}
360
361
362
363DLLEXPORT void *trace_get_payload_from_layer2(void *link,
364                libtrace_linktype_t linktype,
365                uint16_t *ethertype,
366                uint32_t *remaining)
367{
368        void *l;
369        assert(linktype != ~0U);
370        switch(linktype) {
371                /* Packet Metadata headers, not layer2 headers */
372                case TRACE_TYPE_80211_PRISM:
373                case TRACE_TYPE_80211_RADIO:
374                case TRACE_TYPE_PFLOG:
375                case TRACE_TYPE_LINUX_SLL:
376                        return NULL;
377
378                /* duck packets have no payload! */
379                case TRACE_TYPE_DUCK:
380                        return NULL;
381
382                /* The payload is in these packets does
383                   not correspond to a genuine link-layer
384                   */
385                case TRACE_TYPE_METADATA:
386                case TRACE_TYPE_NONDATA:
387                        return NULL;
388
389                case TRACE_TYPE_80211:
390                        return trace_get_payload_from_80211(link,ethertype,remaining);
391                case TRACE_TYPE_ETH:
392                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
393                case TRACE_TYPE_NONE:
394                        if ((*(char*)link&0xF0) == 0x40)
395                                *ethertype=TRACE_ETHERTYPE_IP;   /* IPv4 */
396                        else if ((*(char*)link&0xF0) == 0x60)
397                                *ethertype=TRACE_ETHERTYPE_IPV6; /* IPv6 */
398                        return link; /* I love the simplicity */
399                case TRACE_TYPE_PPP:
400                        return trace_get_payload_from_ppp(link,ethertype,remaining);
401                case TRACE_TYPE_ATM:
402                        l=trace_get_payload_from_atm(link,NULL,remaining);
403                        /* FIXME: We shouldn't skip llcsnap here, we should
404                         * return an ethertype for it (somehow)
405                         */
406                        return (l ? trace_get_payload_from_llcsnap(l,
407                                                ethertype, remaining):NULL);
408                case TRACE_TYPE_LLCSNAP:
409                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
410
411                case TRACE_TYPE_HDLC_POS:
412                        return trace_get_payload_from_chdlc(link,ethertype,
413                                        remaining);
414                case TRACE_TYPE_POS:
415                        return trace_get_payload_from_chdlc(link,ethertype,
416                                        remaining);
417                /* TODO: Unsupported */
418                case TRACE_TYPE_AAL5:
419                        return NULL;
420        }
421        return NULL;
422
423}
424
425/* Take a pointer to the start of an IEEE 802.11 MAC frame and return a pointer
426 * to the source MAC address. 
427 * If the frame does not contain a sender address, e.g. ACK frame, return NULL.
428 * If the frame is a 4-address WDS frame, return TA, i.e. addr2.
429 * NB: This function decodes the 802.11 header, so it assumes that there are no
430 * bit-errors. If there are, all bets are off.
431 */
432static
433uint8_t *get_source_mac_from_wifi(void *wifi) {
434        struct libtrace_80211_t *w;
435        if (wifi == NULL) return NULL;
436        w = (struct libtrace_80211_t *) wifi;
437
438        /* If the frame is of type CTRL */
439        if (w->type == 0x1)
440                /* If bit 2 of the subtype field is zero, this indicates that
441                 * there is no transmitter address, i.e. the frame is either an
442                 * ACK or a CTS frame */
443                if ((w->subtype & 0x2) == 0)
444                        return NULL;
445
446        /* Always return the address of the transmitter, i.e. address 2 */
447        return (uint8_t *) &w->mac2;
448}
449
450DLLEXPORT uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
451        void *link;
452        uint32_t remaining;
453        libtrace_linktype_t linktype;
454        assert(packet);
455        link = trace_get_layer2(packet,&linktype,&remaining);
456
457        if (!link)
458                return NULL;
459
460        switch (linktype) {
461                case TRACE_TYPE_ETH:
462                        return (uint8_t *)&(((libtrace_ether_t*)link)->ether_shost);
463                case TRACE_TYPE_80211:
464                        return get_source_mac_from_wifi(link);
465                /* These packets don't have MAC addresses */
466                case TRACE_TYPE_POS:
467                case TRACE_TYPE_NONE:
468                case TRACE_TYPE_HDLC_POS:
469                case TRACE_TYPE_PFLOG:
470                case TRACE_TYPE_ATM:
471                case TRACE_TYPE_DUCK:
472                case TRACE_TYPE_METADATA:
473                case TRACE_TYPE_AAL5:
474                case TRACE_TYPE_LLCSNAP:
475                case TRACE_TYPE_PPP:
476                case TRACE_TYPE_NONDATA:
477                        return NULL;
478
479                /* Metadata headers should already be skipped */
480                case TRACE_TYPE_LINUX_SLL:
481                case TRACE_TYPE_80211_PRISM:
482                case TRACE_TYPE_80211_RADIO:
483                        assert(!"Metadata headers should already be skipped");
484                        break;
485        }
486        fprintf(stderr,"%s not implemented for linktype %i\n", __func__, linktype);
487        assert(0);
488        return NULL;
489}
490
491DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet)
492{
493        void *link;
494        libtrace_linktype_t linktype;
495        uint32_t remaining;
496        libtrace_80211_t *wifi;
497        libtrace_ether_t *ethptr;
498
499        link = trace_get_layer2(packet,&linktype,&remaining);
500
501        ethptr = (libtrace_ether_t*)link;
502
503
504        if (!link)
505                return NULL;
506
507        switch (linktype) {
508                case TRACE_TYPE_80211:
509                        wifi=(libtrace_80211_t*)link;
510                        return (uint8_t*)&wifi->mac1;
511                case TRACE_TYPE_ETH:
512                        return (uint8_t*)&ethptr->ether_dhost;
513                case TRACE_TYPE_POS:
514                case TRACE_TYPE_NONE:
515                case TRACE_TYPE_ATM:
516                case TRACE_TYPE_HDLC_POS:
517                case TRACE_TYPE_PFLOG:
518                case TRACE_TYPE_DUCK:
519                case TRACE_TYPE_METADATA:
520                case TRACE_TYPE_AAL5:
521                case TRACE_TYPE_LLCSNAP:
522                case TRACE_TYPE_PPP:   
523                case TRACE_TYPE_NONDATA:
524                        /* No MAC address */
525                        return NULL;
526                /* Metadata headers should already be skipped */
527                case TRACE_TYPE_LINUX_SLL:
528                case TRACE_TYPE_80211_PRISM:
529                case TRACE_TYPE_80211_RADIO:
530                        assert(!"Metadata headers should already be skipped");
531                        break;
532        }
533        fprintf(stderr,"Not implemented\n");
534        assert(0);
535        return NULL;
536}
537
Note: See TracBrowser for help on using the repository browser.