source: lib/protocols_l2.c @ 3ac4bf7

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 3ac4bf7 was 3ac4bf7, checked in by Shane Alcock <salcock@…>, 14 years ago
  • Fixing more variables that aren't declared at the beginning of a code block
  • Property mode set to 100644
File size: 7.5 KB
Line 
1/* Protocol decodes for layer 2 */
2#include "libtrace.h"
3#include "protocols.h"
4#include "libtrace_int.h"
5#include <assert.h>
6
7/* Returns the payload from 802.3 ethernet.  Type optionally returned in
8 * "type" in host byte order.  This will return a vlan header.
9 */
10void *trace_get_payload_from_ethernet(void *ethernet, 
11                uint16_t *type,
12                uint32_t *remaining)
13{
14        libtrace_ether_t *eth = (libtrace_ether_t*)ethernet;
15
16        if (remaining) {
17                if (*remaining < sizeof(*eth))
18                        return NULL;
19                *remaining-=sizeof(*eth);
20        }
21
22        if (type)
23                *type = ntohs(eth->ether_type);
24
25        return (void*)((char *)eth + sizeof(*eth));
26}
27
28/* skip any 802.1q headers if necessary
29 * type is input/output
30 */
31void *trace_get_vlan_payload_from_ethernet_payload(void *ethernet, uint16_t *type,
32                uint32_t *remaining)
33{
34        if (*type == 0x8100) {
35                libtrace_8021q_t *vlanhdr = (libtrace_8021q_t *)ethernet;
36
37                if (remaining) {
38                        if (*remaining <= sizeof(libtrace_8021q_t))
39                                return NULL;
40
41                        *remaining=*remaining-sizeof(libtrace_8021q_t);
42                }
43
44                *type = ntohs(vlanhdr->vlan_ether_type);
45
46                return (void*)((char *)ethernet + sizeof(*vlanhdr));
47        }
48
49        return ethernet;
50}
51
52/* skip any MPLS headers if necessary, guessing what the next type is
53 * type is input/output.  If the next type is "ethernet" this will
54 * return a type of 0x0000.
55 */
56void *trace_get_mpls_payload_from_ethernet_payload(void *ethernet,
57                uint16_t *type, uint32_t *remaining)
58{
59        if (*type == 0x8847) {
60                if ((((char*)ethernet)[2]&0x01)==0) {
61                        *type = 0x8847;
62                }
63                else {
64                        if (!remaining || *remaining>=5) {
65                                switch (((char*)ethernet)[4]&0xF0) {
66                                        case 0x40:
67                                                *type = 0x0800;
68                                                break;
69                                        case 0x60:
70                                                *type = 0x86DD;
71                                                break;
72                                        default:
73                                                /* Ethernet */
74                                                *type = 0;
75                                }
76                        }
77                }
78                ethernet=(char*)ethernet+4;
79                if (remaining) {
80                        if (*remaining<=4)
81                                return NULL;
82                        else
83                                *remaining-=4;
84                }
85
86
87                return ethernet;
88        }
89        else
90                return NULL;
91}
92
93static void *trace_get_payload_from_llcsnap(void *link,
94                uint16_t *type, uint32_t *remaining)
95{
96        /* 64 byte capture. */
97        libtrace_llcsnap_t *llc = (libtrace_llcsnap_t*)link;
98
99        if (remaining) {
100                if (*remaining <= sizeof(libtrace_llcsnap_t))
101                        return NULL;
102                *remaining-=(sizeof(libtrace_llcsnap_t));
103        }
104
105        llc = (libtrace_llcsnap_t*)((char *)llc);
106
107        if (type) *type = ntohs(llc->type);
108
109        return (void*)((char*)llc+sizeof(*llc));
110}
111
112
113static void *trace_get_payload_from_80211(void *link, uint16_t *type, uint32_t *remaining)
114{
115        libtrace_80211_t *wifi;
116        uint16_t *eth; /* ethertype */
117        int8_t extra = 0; /* how many QoS bytes to skip */
118       
119        if (remaining && *remaining <= sizeof(libtrace_80211_t))
120                return NULL;
121
122        wifi=(libtrace_80211_t*)link;
123
124        /* Data packet? */
125        if (wifi->type != 2) {
126                return NULL;
127        }
128
129        /* If FromDS and ToDS are both set then we have a four-address
130         * frame. Otherwise we have a three-address frame */
131        if (!(wifi->to_ds && wifi->from_ds)) 
132                extra -= 6; 
133       
134        /* Indicates QoS field present, see IEEE802.11e-2005 pg 21 */
135        if (wifi->subtype & 0x8) 
136                extra += 2;
137
138        if (remaining && *remaining < sizeof(*eth))
139                return NULL;
140
141        eth=(uint16_t *)((char*)wifi+sizeof(*wifi)+extra);
142       
143        if (*eth == 0xaaaa)
144                /* Payload contains an 802.2 LLC/SNAP frame */
145                return trace_get_payload_from_llcsnap((void *)eth, type, remaining);
146                       
147        /* Otherwise we assume an Ethernet II frame */
148        if (type) *type=ntohs(*eth);
149        if (remaining) *remaining = *remaining - sizeof(libtrace_80211_t) - extra - sizeof(*eth);
150       
151        return (void*)((char*)eth+sizeof(*eth));
152}
153
154static void *trace_get_payload_from_ppp(void *link, 
155                uint16_t *type, uint32_t *remaining)
156{
157        /* 64 byte capture. */
158        libtrace_ppp_t *ppp = (libtrace_ppp_t*)link;
159
160        if (remaining) {
161                if (*remaining <= sizeof(libtrace_ppp_t))
162                        return NULL;
163                *remaining-=sizeof(libtrace_ppp_t);
164        }
165
166        if (type) {
167                switch(ntohs(ppp->protocol)) {
168                        case 0x0021: *type = 0x0800; break;
169                }
170        }
171
172
173        return (void*)((char *)ppp+sizeof(*ppp));
174}
175
176typedef struct libtrace_chdlc_t {
177        uint8_t address;        /** 0xF0 for unicast, 0xF8 for multicast */
178        uint8_t control;
179        uint16_t ethertype;
180} libtrace_chdlc_t;
181
182static void *trace_get_payload_from_chdlc(void *link, 
183                uint16_t *type, uint32_t *remaining)
184{
185        libtrace_chdlc_t *chdlc = (libtrace_chdlc_t*)link;
186
187        if (remaining) {
188                if (*remaining <= sizeof(libtrace_chdlc_t))
189                        return NULL;
190                *remaining-=sizeof(libtrace_chdlc_t);
191        }
192
193        if (type) {
194                *type=ntohs(chdlc->ethertype);
195        }
196
197
198        return (void*)((char *)chdlc+sizeof(*chdlc));
199}
200
201void *trace_get_payload_from_link(void *link, libtrace_linktype_t linktype, 
202                uint16_t *ethertype, uint32_t *remaining)
203{
204        void *l = NULL;
205
206        do {
207                l = trace_get_payload_from_meta(link, &linktype, remaining);
208                if (l != NULL) {
209                        link=l;
210                        continue;
211                }
212        } while (0);
213
214        return trace_get_payload_from_layer2(link,linktype,ethertype,remaining);
215       
216}
217
218DLLEXPORT void *trace_get_layer2(const libtrace_packet_t *packet,
219                libtrace_linktype_t *linktype,
220                uint32_t *remaining) 
221{
222        uint32_t dummyrem;
223        void *meta = NULL;
224       
225        assert(packet != NULL);
226        assert(linktype != NULL);
227
228        if (remaining == NULL)
229                remaining = &dummyrem;
230       
231        meta = trace_get_packet_meta(packet, linktype, remaining);
232
233        /* If there are no meta-data headers, we just return the start of the
234         * packet buffer, along with the linktype, etc.
235         */
236        if (meta == NULL) 
237                return trace_get_packet_buffer(packet, linktype, remaining);
238       
239        /* If there are meta-data headers, we need to skip over them until we
240         * find a non-meta data header and return that.
241         */
242        for(;;) {
243                void *nexthdr = trace_get_payload_from_meta(meta, 
244                                linktype, remaining);
245                if (nexthdr == NULL)
246                        return meta;
247                meta = nexthdr;
248        }
249}
250
251DLLEXPORT
252void *trace_get_payload_from_atm(void *link,
253                uint8_t *type, uint32_t *remaining)
254{
255        libtrace_atm_capture_cell_t *cell;
256        if (remaining && *remaining<=sizeof(libtrace_atm_capture_cell_t))
257                return NULL;
258        cell=(libtrace_atm_capture_cell_t*)link;
259
260        if (type)
261                *type=cell->pt;
262
263        if (remaining)
264                *remaining-=sizeof(libtrace_atm_capture_cell_t);
265
266        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
267}
268
269
270
271DLLEXPORT void *trace_get_payload_from_layer2(void *link,
272                libtrace_linktype_t linktype,
273                uint16_t *ethertype,
274                uint32_t *remaining)
275{
276        void *l;
277        switch(linktype) {
278                /* Packet Metadata headers, not layer2 headers */
279                case TRACE_TYPE_80211_PRISM:
280                case TRACE_TYPE_80211_RADIO:
281                case TRACE_TYPE_PFLOG:
282                case TRACE_TYPE_LINUX_SLL:
283                        return NULL;
284
285                /* duck packets have no payload! */
286                case TRACE_TYPE_DUCK:
287                        return NULL;
288
289                /* The payload is in these packets does
290                   not correspond to a genuine link-layer
291                   */
292                case TRACE_TYPE_METADATA:
293                        return NULL;
294
295                case TRACE_TYPE_80211:
296                        return trace_get_payload_from_80211(link,ethertype,remaining);
297                case TRACE_TYPE_ETH:
298                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
299                case TRACE_TYPE_NONE:
300                        if ((*(char*)link&0xF0) == 0x40)
301                                *ethertype=0x0800;
302                        else if ((*(char*)link&0xF0) == 0x60)
303                                *ethertype=0x86DD;
304                        return link; /* I love the simplicity */
305                case TRACE_TYPE_PPP:
306                        return trace_get_payload_from_ppp(link,ethertype,remaining);
307                case TRACE_TYPE_ATM:
308                        l=trace_get_payload_from_atm(link,NULL,remaining);
309                        /* FIXME: We shouldn't skip llcsnap here, we should return
310                         * an ethertype for it (somehow)
311                         */
312                        return (l ? trace_get_payload_from_llcsnap(l,
313                                                ethertype, remaining):NULL);
314                case TRACE_TYPE_LLCSNAP:
315                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
316
317                case TRACE_TYPE_HDLC_POS:
318                        return trace_get_payload_from_chdlc(link,ethertype,
319                                        remaining);
320                /* TODO: Unsupported */
321                case TRACE_TYPE_POS:
322                case TRACE_TYPE_AAL5:
323                        return NULL;
324        }
325        return NULL;
326
327}
328
329
330
Note: See TracBrowser for help on using the repository browser.