source: lib/protocols_l2.c @ 530cef6

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