source: lib/protocols_l2.c @ ae8ec56

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