source: lib/protocols_l2.c @ aa22b5b

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since aa22b5b was aa22b5b, checked in by Perry Lorier <perry@…>, 13 years ago

If we have a complete header, but truncated at the end of it, we shouldn't return NULL from
get_payload_from_* functions so we can distinguish it from a truncated header.

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