• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2007 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /**
21  * SECTION:element-pcapparse
22  * @title: pcapparse
23  *
24  * Extracts payloads from Ethernet-encapsulated IP packets.
25  * Use #GstPcapParse:src-ip, #GstPcapParse:dst-ip,
26  * #GstPcapParse:src-port and #GstPcapParse:dst-port to restrict which packets
27  * should be included.
28  *
29  * The supported data format is the classical
30  * [libpcap file format](https://wiki.wireshark.org/Development/LibpcapFileFormat)
31  *
32  * ## Example pipelines
33  * |[
34  * gst-launch-1.0 filesrc location=h264crasher.pcap ! pcapparse ! rtph264depay
35  * ! ffdec_h264 ! fakesink
36  * ]| Read from a pcap dump file using filesrc, extract the raw UDP packets,
37  * depayload and decode them.
38  *
39  */
40 
41 /* TODO:
42  * - Implement support for timestamping the buffers.
43  */
44 
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48 
49 #include "gstpcapparse.h"
50 
51 #include <string.h>
52 
53 #ifndef G_OS_WIN32
54 #include <arpa/inet.h>
55 #include <netinet/in.h>
56 #include <string.h>
57 #else
58 #include <winsock2.h>
59 #endif
60 
61 
62 const guint GST_PCAPPARSE_MAGIC_MILLISECOND_NO_SWAP_ENDIAN = 0xa1b2c3d4;
63 const guint GST_PCAPPARSE_MAGIC_NANOSECOND_NO_SWAP_ENDIAN = 0xa1b23c4d;
64 const guint GST_PCAPPARSE_MAGIC_MILLISECOND_SWAP_ENDIAN = 0xd4c3b2a1;
65 const guint GST_PCAPPARSE_MAGIC_NANOSECOND_SWAP_ENDIAN = 0x4d3cb2a1;
66 
67 
68 enum
69 {
70   PROP_0,
71   PROP_SRC_IP,
72   PROP_DST_IP,
73   PROP_SRC_PORT,
74   PROP_DST_PORT,
75   PROP_CAPS,
76   PROP_TS_OFFSET
77 };
78 
79 GST_DEBUG_CATEGORY_STATIC (gst_pcap_parse_debug);
80 #define GST_CAT_DEFAULT gst_pcap_parse_debug
81 
82 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
83     GST_PAD_SINK,
84     GST_PAD_ALWAYS,
85     GST_STATIC_CAPS ("raw/x-pcap"));
86 
87 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
88     GST_PAD_SRC,
89     GST_PAD_ALWAYS,
90     GST_STATIC_CAPS_ANY);
91 
92 static void gst_pcap_parse_finalize (GObject * object);
93 static void gst_pcap_parse_get_property (GObject * object, guint prop_id,
94     GValue * value, GParamSpec * pspec);
95 static void gst_pcap_parse_set_property (GObject * object, guint prop_id,
96     const GValue * value, GParamSpec * pspec);
97 static GstStateChangeReturn
98 gst_pcap_parse_change_state (GstElement * element, GstStateChange transition);
99 
100 static void gst_pcap_parse_reset (GstPcapParse * self);
101 
102 static GstFlowReturn gst_pcap_parse_chain (GstPad * pad,
103     GstObject * parent, GstBuffer * buffer);
104 static gboolean gst_pcap_sink_event (GstPad * pad,
105     GstObject * parent, GstEvent * event);
106 
107 
108 #define parent_class gst_pcap_parse_parent_class
109 G_DEFINE_TYPE (GstPcapParse, gst_pcap_parse, GST_TYPE_ELEMENT);
110 GST_ELEMENT_REGISTER_DEFINE (pcapparse, "pcapparse", GST_RANK_NONE,
111     GST_TYPE_PCAP_PARSE);
112 
113 static void
gst_pcap_parse_class_init(GstPcapParseClass * klass)114 gst_pcap_parse_class_init (GstPcapParseClass * klass)
115 {
116   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
117   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
118 
119   gobject_class->finalize = gst_pcap_parse_finalize;
120   gobject_class->get_property = gst_pcap_parse_get_property;
121   gobject_class->set_property = gst_pcap_parse_set_property;
122 
123   g_object_class_install_property (gobject_class,
124       PROP_SRC_IP, g_param_spec_string ("src-ip", "Source IP",
125           "Source IP to restrict to", "",
126           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
127 
128   g_object_class_install_property (gobject_class,
129       PROP_DST_IP, g_param_spec_string ("dst-ip", "Destination IP",
130           "Destination IP to restrict to", "",
131           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
132 
133   g_object_class_install_property (gobject_class,
134       PROP_SRC_PORT, g_param_spec_int ("src-port", "Source port",
135           "Source port to restrict to", -1, G_MAXUINT16, -1,
136           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
137 
138   g_object_class_install_property (gobject_class,
139       PROP_DST_PORT, g_param_spec_int ("dst-port", "Destination port",
140           "Destination port to restrict to", -1, G_MAXUINT16, -1,
141           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
142 
143   g_object_class_install_property (gobject_class, PROP_CAPS,
144       g_param_spec_boxed ("caps", "Caps",
145           "The caps of the source pad", GST_TYPE_CAPS,
146           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
147 
148   g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
149       g_param_spec_int64 ("ts-offset", "Timestamp Offset",
150           "Relative timestamp offset (ns) to apply (-1 = use absolute packet time)",
151           -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152 
153   gst_element_class_add_static_pad_template (element_class, &sink_template);
154   gst_element_class_add_static_pad_template (element_class, &src_template);
155 
156   element_class->change_state = gst_pcap_parse_change_state;
157 
158   gst_element_class_set_static_metadata (element_class, "PCapParse",
159       "Raw/Parser",
160       "Parses a raw pcap stream",
161       "Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>");
162 
163   GST_DEBUG_CATEGORY_INIT (gst_pcap_parse_debug, "pcapparse", 0, "pcap parser");
164 }
165 
166 static void
gst_pcap_parse_init(GstPcapParse * self)167 gst_pcap_parse_init (GstPcapParse * self)
168 {
169   self->sink_pad = gst_pad_new_from_static_template (&sink_template, "sink");
170   gst_pad_set_chain_function (self->sink_pad,
171       GST_DEBUG_FUNCPTR (gst_pcap_parse_chain));
172   gst_pad_use_fixed_caps (self->sink_pad);
173   gst_pad_set_event_function (self->sink_pad,
174       GST_DEBUG_FUNCPTR (gst_pcap_sink_event));
175   gst_element_add_pad (GST_ELEMENT (self), self->sink_pad);
176 
177   self->src_pad = gst_pad_new_from_static_template (&src_template, "src");
178   gst_pad_use_fixed_caps (self->src_pad);
179   gst_element_add_pad (GST_ELEMENT (self), self->src_pad);
180 
181   self->src_ip = -1;
182   self->dst_ip = -1;
183   self->src_port = -1;
184   self->dst_port = -1;
185   self->offset = -1;
186 
187   self->adapter = gst_adapter_new ();
188 
189   gst_pcap_parse_reset (self);
190 }
191 
192 static void
gst_pcap_parse_finalize(GObject * object)193 gst_pcap_parse_finalize (GObject * object)
194 {
195   GstPcapParse *self = GST_PCAP_PARSE (object);
196 
197   g_object_unref (self->adapter);
198   if (self->caps)
199     gst_caps_unref (self->caps);
200 
201   G_OBJECT_CLASS (parent_class)->finalize (object);
202 }
203 
204 static const gchar *
get_ip_address_as_string(gint64 ip_addr)205 get_ip_address_as_string (gint64 ip_addr)
206 {
207   if (ip_addr >= 0) {
208     struct in_addr addr;
209     addr.s_addr = ip_addr;
210     return inet_ntoa (addr);
211   } else {
212     return "";
213   }
214 }
215 
216 static void
set_ip_address_from_string(gint64 * ip_addr,const gchar * ip_str)217 set_ip_address_from_string (gint64 * ip_addr, const gchar * ip_str)
218 {
219   if (ip_str[0] != '\0') {
220     gulong addr = inet_addr (ip_str);
221     if (addr != INADDR_NONE)
222       *ip_addr = addr;
223   } else {
224     *ip_addr = -1;
225   }
226 }
227 
228 static void
gst_pcap_parse_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)229 gst_pcap_parse_get_property (GObject * object, guint prop_id,
230     GValue * value, GParamSpec * pspec)
231 {
232   GstPcapParse *self = GST_PCAP_PARSE (object);
233 
234   switch (prop_id) {
235     case PROP_SRC_IP:
236       g_value_set_string (value, get_ip_address_as_string (self->src_ip));
237       break;
238 
239     case PROP_DST_IP:
240       g_value_set_string (value, get_ip_address_as_string (self->dst_ip));
241       break;
242 
243     case PROP_SRC_PORT:
244       g_value_set_int (value, self->src_port);
245       break;
246 
247     case PROP_DST_PORT:
248       g_value_set_int (value, self->dst_port);
249       break;
250 
251     case PROP_CAPS:
252       gst_value_set_caps (value, self->caps);
253       break;
254 
255     case PROP_TS_OFFSET:
256       g_value_set_int64 (value, self->offset);
257       break;
258 
259     default:
260       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261       break;
262   }
263 }
264 
265 static void
gst_pcap_parse_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)266 gst_pcap_parse_set_property (GObject * object, guint prop_id,
267     const GValue * value, GParamSpec * pspec)
268 {
269   GstPcapParse *self = GST_PCAP_PARSE (object);
270 
271   switch (prop_id) {
272     case PROP_SRC_IP:
273       set_ip_address_from_string (&self->src_ip, g_value_get_string (value));
274       break;
275 
276     case PROP_DST_IP:
277       set_ip_address_from_string (&self->dst_ip, g_value_get_string (value));
278       break;
279 
280     case PROP_SRC_PORT:
281       self->src_port = g_value_get_int (value);
282       break;
283 
284     case PROP_DST_PORT:
285       self->dst_port = g_value_get_int (value);
286       break;
287 
288     case PROP_CAPS:
289     {
290       const GstCaps *new_caps_val;
291       GstCaps *new_caps, *old_caps;
292 
293       new_caps_val = gst_value_get_caps (value);
294       if (new_caps_val == NULL) {
295         new_caps = gst_caps_new_any ();
296       } else {
297         new_caps = gst_caps_copy (new_caps_val);
298       }
299 
300       old_caps = self->caps;
301       self->caps = new_caps;
302       if (old_caps)
303         gst_caps_unref (old_caps);
304 
305       gst_pad_set_caps (self->src_pad, new_caps);
306       break;
307     }
308 
309     case PROP_TS_OFFSET:
310       self->offset = g_value_get_int64 (value);
311       break;
312 
313     default:
314       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315       break;
316   }
317 }
318 
319 static void
gst_pcap_parse_reset(GstPcapParse * self)320 gst_pcap_parse_reset (GstPcapParse * self)
321 {
322   self->initialized = FALSE;
323   self->swap_endian = FALSE;
324   self->nanosecond_timestamp = FALSE;
325   self->cur_packet_size = -1;
326   self->cur_ts = GST_CLOCK_TIME_NONE;
327   self->base_ts = GST_CLOCK_TIME_NONE;
328   self->newsegment_sent = FALSE;
329   self->first_packet = TRUE;
330 
331   gst_adapter_clear (self->adapter);
332 }
333 
334 static guint32
gst_pcap_parse_read_uint32(GstPcapParse * self,const guint8 * p)335 gst_pcap_parse_read_uint32 (GstPcapParse * self, const guint8 * p)
336 {
337   guint32 val = *((guint32 *) p);
338 
339   if (self->swap_endian) {
340 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
341     return GUINT32_FROM_BE (val);
342 #else
343     return GUINT32_FROM_LE (val);
344 #endif
345   } else {
346     return val;
347   }
348 }
349 
350 #define ETH_MAC_ADDRESSES_LEN    12
351 #define ETH_HEADER_LEN    14
352 #define ETH_VLAN_HEADER_LEN    4
353 #define SLL_HEADER_LEN    16
354 #define IP_HEADER_MIN_LEN 20
355 #define UDP_HEADER_LEN     8
356 
357 #define IP_PROTO_UDP      17
358 #define IP_PROTO_TCP      6
359 
360 
361 static gboolean
gst_pcap_parse_scan_frame(GstPcapParse * self,const guint8 * buf,gint buf_size,const guint8 ** payload,gint * payload_size)362 gst_pcap_parse_scan_frame (GstPcapParse * self,
363     const guint8 * buf,
364     gint buf_size, const guint8 ** payload, gint * payload_size)
365 {
366   const guint8 *buf_ip = 0;
367   const guint8 *buf_proto;
368   guint16 eth_type;
369   guint8 b;
370   guint8 ip_header_size;
371   guint8 flags;
372   guint16 fragment_offset;
373   guint8 ip_protocol;
374   guint32 ip_src_addr;
375   guint32 ip_dst_addr;
376   guint16 src_port;
377   guint16 dst_port;
378   guint16 len;
379   guint16 ip_packet_len;
380 
381   switch (self->linktype) {
382     case LINKTYPE_ETHER:
383       if (buf_size < ETH_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
384         return FALSE;
385       eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + ETH_MAC_ADDRESSES_LEN)));
386       /* check for vlan 802.1q header (4 bytes, with first two bytes equal to 0x8100)  */
387       if (eth_type == 0x8100) {
388         if (buf_size <
389             ETH_HEADER_LEN + ETH_VLAN_HEADER_LEN + IP_HEADER_MIN_LEN +
390             UDP_HEADER_LEN)
391           return FALSE;
392         eth_type =
393             GUINT16_FROM_BE (*((guint16 *) (buf + ETH_MAC_ADDRESSES_LEN +
394                     ETH_VLAN_HEADER_LEN)));
395         buf_ip = buf + ETH_HEADER_LEN + ETH_VLAN_HEADER_LEN;
396       } else {
397         buf_ip = buf + ETH_HEADER_LEN;
398       }
399       break;
400     case LINKTYPE_SLL:
401       if (buf_size < SLL_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
402         return FALSE;
403 
404       eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + 14)));
405       buf_ip = buf + SLL_HEADER_LEN;
406       break;
407     case LINKTYPE_RAW:
408       if (buf_size < IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
409         return FALSE;
410 
411       eth_type = 0x800;         /* This is fine since IPv4/IPv6 is parse elsewhere */
412       buf_ip = buf;
413       break;
414 
415     default:
416       return FALSE;
417   }
418 
419   if (eth_type != 0x800) {
420     GST_ERROR_OBJECT (self,
421         "Link type %d: Ethernet type %d is not supported; only type 0x800",
422         (gint) self->linktype, (gint) eth_type);
423     return FALSE;
424   }
425 
426   b = *buf_ip;
427 
428   /* Check that the packet is IPv4 */
429   if (((b >> 4) & 0x0f) != 4)
430     return FALSE;
431 
432   ip_header_size = (b & 0x0f) * 4;
433   if (buf_ip + ip_header_size > buf + buf_size)
434     return FALSE;
435 
436   flags = buf_ip[6] >> 5;
437   fragment_offset =
438       (GUINT16_FROM_BE (*((guint16 *) (buf_ip + 6))) & 0x1fff) * 8;
439   if (flags & 0x1 || fragment_offset > 0) {
440     GST_ERROR_OBJECT (self, "Fragmented packets are not supported");
441     return FALSE;
442   }
443 
444   ip_protocol = *(buf_ip + 9);
445   GST_LOG_OBJECT (self, "ip proto %d", (gint) ip_protocol);
446 
447   if (ip_protocol != IP_PROTO_UDP && ip_protocol != IP_PROTO_TCP)
448     return FALSE;
449 
450   /* ip info */
451   ip_src_addr = *((guint32 *) (buf_ip + 12));
452   ip_dst_addr = *((guint32 *) (buf_ip + 16));
453   buf_proto = buf_ip + ip_header_size;
454   ip_packet_len = GUINT16_FROM_BE (*(guint16 *) (buf_ip + 2));
455 
456   /* ok for tcp and udp */
457   src_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 0)));
458   dst_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 2)));
459 
460   /* extract some params and data according to protocol */
461   if (ip_protocol == IP_PROTO_UDP) {
462     len = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 4)));
463     if (len < UDP_HEADER_LEN || buf_proto + len > buf + buf_size)
464       return FALSE;
465 
466     *payload = buf_proto + UDP_HEADER_LEN;
467     *payload_size = len - UDP_HEADER_LEN;
468   } else {
469     if (buf_proto + 12 >= buf + buf_size)
470       return FALSE;
471     len = (buf_proto[12] >> 4) * 4;
472     if (buf_proto + len > buf + buf_size)
473       return FALSE;
474 
475     /* all remaining data following tcp header is payload */
476     *payload = buf_proto + len;
477     *payload_size = ip_packet_len - ip_header_size - len;
478   }
479 
480   /* but still filter as configured */
481   if (self->src_ip >= 0 && ip_src_addr != self->src_ip)
482     return FALSE;
483 
484   if (self->dst_ip >= 0 && ip_dst_addr != self->dst_ip)
485     return FALSE;
486 
487   if (self->src_port >= 0 && src_port != self->src_port)
488     return FALSE;
489 
490   if (self->dst_port >= 0 && dst_port != self->dst_port)
491     return FALSE;
492 
493   return TRUE;
494 }
495 
496 static GstFlowReturn
gst_pcap_parse_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)497 gst_pcap_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
498 {
499   GstPcapParse *self = GST_PCAP_PARSE (parent);
500   GstFlowReturn ret = GST_FLOW_OK;
501   GstBufferList *list = NULL;
502 
503   gst_adapter_push (self->adapter, buffer);
504 
505   while (ret == GST_FLOW_OK) {
506     gint avail;
507     const guint8 *data;
508 
509     avail = gst_adapter_available (self->adapter);
510 
511     if (self->initialized) {
512       if (self->cur_packet_size >= 0) {
513         /* Parse the Packet Data */
514         if (avail < self->cur_packet_size)
515           break;
516 
517         if (self->cur_packet_size > 0) {
518           const guint8 *payload_data;
519           gint payload_size;
520 
521           data = gst_adapter_map (self->adapter, self->cur_packet_size);
522 
523           GST_LOG_OBJECT (self, "examining packet size %" G_GINT64_FORMAT,
524               self->cur_packet_size);
525 
526           if (gst_pcap_parse_scan_frame (self, data, self->cur_packet_size,
527                   &payload_data, &payload_size)) {
528             GstBuffer *out_buf;
529             guintptr offset = payload_data - data;
530 
531             gst_adapter_unmap (self->adapter);
532             gst_adapter_flush (self->adapter, offset);
533             /* we don't use _take_buffer_fast() on purpose here, we need a
534              * buffer with a single memory, since the RTP depayloaders expect
535              * the complete RTP header to be in the first memory if there are
536              * multiple ones and we can't guarantee that with _fast() */
537             if (payload_size > 0) {
538               out_buf = gst_adapter_take_buffer (self->adapter, payload_size);
539             } else {
540               out_buf = gst_buffer_new ();
541             }
542 
543             /* only first packet should have DISCONT flag */
544             if (G_LIKELY (!self->first_packet)) {
545               GST_BUFFER_FLAG_UNSET (out_buf, GST_BUFFER_FLAG_DISCONT);
546             } else {
547               GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT);
548               self->first_packet = FALSE;
549             }
550 
551             gst_adapter_flush (self->adapter,
552                 self->cur_packet_size - offset - payload_size);
553 
554             if (GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
555               if (!GST_CLOCK_TIME_IS_VALID (self->base_ts))
556                 self->base_ts = self->cur_ts;
557               if (self->offset >= 0) {
558                 self->cur_ts -= self->base_ts;
559                 self->cur_ts += self->offset;
560               }
561             }
562             GST_BUFFER_DTS (out_buf) = self->cur_ts;
563 
564 
565             if (list == NULL)
566               list = gst_buffer_list_new ();
567             gst_buffer_list_add (list, out_buf);
568           } else {
569             gst_adapter_unmap (self->adapter);
570             gst_adapter_flush (self->adapter, self->cur_packet_size);
571           }
572         }
573 
574         self->cur_packet_size = -1;
575       } else {
576         /* Parse the Record (Packet) Header */
577         guint32 ts_sec;
578         guint32 ts_usec;
579         guint32 incl_len;
580 
581         /* sizeof(pcaprec_hdr_t) == 16 */
582         if (avail < 16)
583           break;
584 
585         data = gst_adapter_map (self->adapter, 16);
586 
587         ts_sec = gst_pcap_parse_read_uint32 (self, data + 0);
588         ts_usec = gst_pcap_parse_read_uint32 (self, data + 4);
589         incl_len = gst_pcap_parse_read_uint32 (self, data + 8);
590         /* orig_len = gst_pcap_parse_read_uint32 (self, data + 12); */
591 
592         gst_adapter_unmap (self->adapter);
593         gst_adapter_flush (self->adapter, 16);
594 
595         self->cur_ts =
596             ts_sec * GST_SECOND +
597             ts_usec * (self->nanosecond_timestamp ? 1 : GST_USECOND);
598         self->cur_packet_size = incl_len;
599       }
600     } else {
601       /* Parse the Global Header */
602       guint32 magic;
603       guint32 linktype;
604       guint16 major_version;
605 
606       /* sizeof(pcap_hdr_t) == 24 */
607       if (avail < 24)
608         break;
609 
610       data = gst_adapter_map (self->adapter, 24);
611 
612       magic = *((guint32 *) data);
613       major_version = *((guint16 *) (data + 4));
614       linktype = *((guint32 *) (data + 20));
615       gst_adapter_unmap (self->adapter);
616 
617       if (magic == GST_PCAPPARSE_MAGIC_MILLISECOND_NO_SWAP_ENDIAN ||
618           magic == GST_PCAPPARSE_MAGIC_NANOSECOND_NO_SWAP_ENDIAN) {
619         self->swap_endian = FALSE;
620         if (magic == GST_PCAPPARSE_MAGIC_NANOSECOND_NO_SWAP_ENDIAN)
621           self->nanosecond_timestamp = TRUE;
622       } else if (magic == GST_PCAPPARSE_MAGIC_MILLISECOND_SWAP_ENDIAN ||
623           magic == GST_PCAPPARSE_MAGIC_NANOSECOND_SWAP_ENDIAN) {
624         self->swap_endian = TRUE;
625         if (magic == GST_PCAPPARSE_MAGIC_NANOSECOND_SWAP_ENDIAN)
626           self->nanosecond_timestamp = TRUE;
627         major_version = GUINT16_SWAP_LE_BE (major_version);
628         linktype = GUINT32_SWAP_LE_BE (linktype);
629       } else {
630         GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
631             ("File is not a libpcap file, magic is %X", magic));
632         ret = GST_FLOW_ERROR;
633         goto out;
634       }
635 
636       if (major_version != 2) {
637         GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
638             ("File is not a libpcap major version 2, but %u", major_version));
639         ret = GST_FLOW_ERROR;
640         goto out;
641       }
642 
643       if (linktype != LINKTYPE_ETHER && linktype != LINKTYPE_SLL &&
644           linktype != LINKTYPE_RAW) {
645         GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
646             ("Only dumps of type Ethernet, raw IP or Linux Cooked (SLL) "
647                 "understood; type %d unknown", linktype));
648         ret = GST_FLOW_ERROR;
649         goto out;
650       }
651 
652       GST_DEBUG_OBJECT (self, "linktype %u", linktype);
653       self->linktype = linktype;
654 
655       gst_adapter_flush (self->adapter, 24);
656       self->initialized = TRUE;
657     }
658   }
659 
660   if (list) {
661     if (!self->newsegment_sent && GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
662       GstSegment segment;
663 
664       if (self->caps)
665         gst_pad_set_caps (self->src_pad, self->caps);
666       gst_segment_init (&segment, GST_FORMAT_TIME);
667       segment.start = self->base_ts;
668       gst_pad_push_event (self->src_pad, gst_event_new_segment (&segment));
669       self->newsegment_sent = TRUE;
670     }
671 
672     ret = gst_pad_push_list (self->src_pad, list);
673     list = NULL;
674   }
675 
676 out:
677 
678   if (list)
679     gst_buffer_list_unref (list);
680 
681   return ret;
682 }
683 
684 static gboolean
gst_pcap_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)685 gst_pcap_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
686 {
687   gboolean ret = TRUE;
688   GstPcapParse *self = GST_PCAP_PARSE (parent);
689 
690   switch (GST_EVENT_TYPE (event)) {
691     case GST_EVENT_SEGMENT:
692       /* Drop it, we'll replace it with our own */
693       gst_event_unref (event);
694       break;
695     case GST_EVENT_FLUSH_STOP:
696       gst_pcap_parse_reset (self);
697       /* Push event down the pipeline so that other elements stop flushing */
698       /* fall through */
699     default:
700       ret = gst_pad_push_event (self->src_pad, event);
701       break;
702   }
703 
704   return ret;
705 }
706 
707 static GstStateChangeReturn
gst_pcap_parse_change_state(GstElement * element,GstStateChange transition)708 gst_pcap_parse_change_state (GstElement * element, GstStateChange transition)
709 {
710   GstPcapParse *self = GST_PCAP_PARSE (element);
711   GstStateChangeReturn ret;
712 
713   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
714 
715   switch (transition) {
716     case GST_STATE_CHANGE_PAUSED_TO_READY:
717       gst_pcap_parse_reset (self);
718       break;
719     default:
720       break;
721   }
722 
723 
724   return ret;
725 }
726