source: lib/protocols_l2.c @ 2d69532

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