From Jakub Zawadzki: for file read progress bars, use the raw offset in
[obnox/wireshark/wip.git] / wiretap / netscreen.c
index 8b63a75f53bd04c87b667564a375e944be9c4c42..dadc4a667931a532201f0a6cb0dc27b11230e41d 100644 (file)
@@ -1,4 +1,6 @@
 /* netscreen.c
+ *
+ * $Id$
  *
  * Juniper NetScreen snoop output parser
  * Created by re-using a lot of code from cosine.c
 
 static gboolean empty_line(const gchar *line);
 static gboolean info_line(const gchar *line);
-static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr);
-static gboolean netscreen_check_file_type(wtap *wth, int *err);
+static gint64 netscreen_seek_next_packet(wtap *wth, int *err, gchar **err_info,
+       char *hdr);
+static gboolean netscreen_check_file_type(wtap *wth, int *err,
+       gchar **err_info);
 static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
        gint64 *data_offset);
 static gboolean netscreen_seek_read(wtap *wth, gint64 seek_off,
        union wtap_pseudo_header *pseudo_header, guint8 *pd,
        int len, int *err, gchar **err_info);
 static int parse_netscreen_rec_hdr(wtap *wth, const char *line,
-       char *cap_int, gboolean *cap_dir,
+       char *cap_int, gboolean *cap_dir, char *cap_dst,
        union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
 static int parse_netscreen_hex_dump(FILE_T fh, int pkt_len, guint8* buf,
        int *err, gchar **err_info);
@@ -108,8 +112,10 @@ static gboolean info_line(const gchar *line)
 
 /* Seeks to the beginning of the next packet, and returns the
    byte offset. Copy the header line to hdr. Returns -1 on failure,
-   and sets "*err" to the error and set hdr as NULL. */
-static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr)
+   and sets "*err" to the error, sets "*err_info" to null or an
+   additional error string, and sets hdr to NULL. */
+static gint64 netscreen_seek_next_packet(wtap *wth, int *err, gchar **err_info,
+    char *hdr)
 {
        gint64 cur_off;
        char buf[NETSCREEN_LINE_LENGTH];
@@ -118,15 +124,14 @@ static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr)
                cur_off = file_tell(wth->fh);
                if (cur_off == -1) {
                        /* Error */
-                       *err = file_error(wth->fh);
+                       *err = file_error(wth->fh, err_info);
                        hdr = NULL;
                        return -1;
                }
                if (file_gets(buf, sizeof(buf), wth->fh) != NULL) {
                        if (strstr(buf, NETSCREEN_REC_MAGIC_STR1) ||
                            strstr(buf, NETSCREEN_REC_MAGIC_STR2)) {
-                               strncpy(hdr, buf, NETSCREEN_LINE_LENGTH-1);
-                               hdr[NETSCREEN_LINE_LENGTH-1] = '\0';
+                               g_strlcpy(hdr, buf, NETSCREEN_LINE_LENGTH);
                                return cur_off;
                        }
                } else {
@@ -134,11 +139,8 @@ static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr)
                                /* We got an EOF. */
                                *err = 0;
                        } else {
-                               /* We (presumably) got an error (there's no
-                                  equivalent to "ferror()" in zlib, alas,
-                                  so we don't have a wrapper to check for
-                                  an error). */
-                               *err = file_error(wth->fh);
+                               /* We got an error. */
+                               *err = file_error(wth->fh, err_info);
                        }
                        break;
                }
@@ -151,9 +153,10 @@ static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr)
  * NetScreen snoop output.
  *
  * Returns TRUE if it is, FALSE if it isn't or if we get an I/O error;
- * if we get an I/O error, "*err" will be set to a non-zero value.
+ * if we get an I/O error, "*err" will be set to a non-zero value and
+ * "*err_info" is set to null or an additional error string.
  */
-static gboolean netscreen_check_file_type(wtap *wth, int *err)
+static gboolean netscreen_check_file_type(wtap *wth, int *err, gchar **err_info)
 {
        char    buf[NETSCREEN_LINE_LENGTH];
        guint   reclen, line;
@@ -163,7 +166,7 @@ static gboolean netscreen_check_file_type(wtap *wth, int *err)
        for (line = 0; line < NETSCREEN_HEADER_LINES_TO_CHECK; line++) {
                if (file_gets(buf, NETSCREEN_LINE_LENGTH, wth->fh) != NULL) {
 
-                       reclen = strlen(buf);
+                       reclen = (guint) strlen(buf);
                        if (reclen < strlen(NETSCREEN_HDR_MAGIC_STR1) ||
                                reclen < strlen(NETSCREEN_HDR_MAGIC_STR2)) {
                                continue;
@@ -178,7 +181,7 @@ static gboolean netscreen_check_file_type(wtap *wth, int *err)
                        if (file_eof(wth->fh))
                                *err = 0;
                        else
-                               *err = file_error(wth->fh);
+                               *err = file_error(wth->fh, err_info);
                        return FALSE;
                }
        }
@@ -187,11 +190,11 @@ static gboolean netscreen_check_file_type(wtap *wth, int *err)
 }
 
 
-int netscreen_open(wtap *wth, int *err, gchar **err_info _U_)
+int netscreen_open(wtap *wth, int *err, gchar **err_info)
 {
 
        /* Look for a NetScreen snoop header line */
-       if (!netscreen_check_file_type(wth, err)) {
+       if (!netscreen_check_file_type(wth, err, err_info)) {
                if (*err == 0)
                        return 0;
                else
@@ -202,7 +205,7 @@ int netscreen_open(wtap *wth, int *err, gchar **err_info _U_)
                return -1;
 
        wth->data_offset = 0;
-       wth->file_encap = WTAP_ENCAP_PER_PACKET;
+       wth->file_encap = WTAP_ENCAP_UNKNOWN;
        wth->file_type = WTAP_FILE_NETSCREEN;
        wth->snapshot_length = 0; /* not known */
        wth->subtype_read = netscreen_read;
@@ -222,14 +225,16 @@ static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
        char            line[NETSCREEN_LINE_LENGTH];
        char            cap_int[NETSCREEN_MAX_INT_NAME_LENGTH];
        gboolean        cap_dir;
+       char            cap_dst[13];
+       gchar           dststr[13];
 
        /* Find the next packet */
-       offset = netscreen_seek_next_packet(wth, err, line);
+       offset = netscreen_seek_next_packet(wth, err, err_info, line);
        if (offset < 0)
                return FALSE;
 
        /* Parse the header */
-       pkt_len = parse_netscreen_rec_hdr(wth, line, cap_int, &cap_dir, 
+       pkt_len = parse_netscreen_rec_hdr(wth, line, cap_int, &cap_dir, cap_dst,
                &wth->pseudo_header, err, err_info);
        if (pkt_len == -1)
                return FALSE;
@@ -244,13 +249,47 @@ static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
                return FALSE;
        }
 
-       if (strncmp(cap_int, "adsl", 4) == 0) 
-               wth->phdr.pkt_encap = WTAP_ENCAP_PPP;
+       /*
+        * Determine the encapsulation type, based on the
+        * first 4 characters of the interface name
+        *
+        * XXX  convert this to a 'case' structure when adding more
+        *      (non-ethernet) interfacetypes
+        */
+       if (strncmp(cap_int, "adsl", 4) == 0) {
+                /* The ADSL interface can be bridged with or without
+                 * PPP encapsulation. Check whether the first six bytes
+                 * of the hex data are the same as the destination mac
+                 * address in the header. If they are, assume ethernet
+                 * LinkLayer or else PPP
+                 */
+                g_snprintf(dststr, 13, "%02x%02x%02x%02x%02x%02x",
+                   buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+                if (strncmp(dststr, cap_dst, 12) == 0) 
+                       wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
+                else
+                       wth->phdr.pkt_encap = WTAP_ENCAP_PPP;
+                }
        else if (strncmp(cap_int, "seri", 4) == 0)
                wth->phdr.pkt_encap = WTAP_ENCAP_PPP;
        else
                wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
 
+       /*
+        * If the per-file encapsulation isn't known, set it to this
+        * packet's encapsulation.
+        *
+        * If it *is* known, and it isn't this packet's encapsulation,
+        * set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
+        * have a single encapsulation for all packets in the file.
+        */
+       if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
+               wth->file_encap = wth->phdr.pkt_encap;
+       else {
+               if (wth->file_encap != wth->phdr.pkt_encap)
+                       wth->file_encap = WTAP_ENCAP_PER_PACKET;
+       }
+
        wth->data_offset = offset;
        wth->phdr.caplen = caplen;
        *data_offset = offset;
@@ -266,25 +305,30 @@ netscreen_seek_read (wtap *wth, gint64 seek_off,
        char            line[NETSCREEN_LINE_LENGTH];
        char            cap_int[NETSCREEN_MAX_INT_NAME_LENGTH];
        gboolean        cap_dir;
+       char            cap_dst[13];
 
        if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
                return FALSE;
        }
 
        if (file_gets(line, NETSCREEN_LINE_LENGTH, wth->random_fh) == NULL) {
-               *err = file_error(wth->random_fh);
+               *err = file_error(wth->random_fh, err_info);
                if (*err == 0) {
                        *err = WTAP_ERR_SHORT_READ;
                }
                return FALSE;
        }
 
-       if (parse_netscreen_rec_hdr(NULL, line, cap_int, &cap_dir, pseudo_header, 
-          err, err_info) == -1) {
+       if (parse_netscreen_rec_hdr(NULL, line, cap_int, &cap_dir, cap_dst,
+           pseudo_header, err, err_info) == -1) {
                return FALSE;
        }
 
-       return parse_netscreen_hex_dump(wth->random_fh, len, pd, err, err_info);
+       if (parse_netscreen_hex_dump(wth->random_fh, len, pd, err, err_info)
+           == -1) {
+               return FALSE;
+       }
+       return TRUE;
 }
 
 /* Parses a packet record header. There are a few possible formats:
@@ -305,15 +349,17 @@ netscreen_seek_read (wtap *wth, gint64 seek_off,
 
  */
 static int
-parse_netscreen_rec_hdr(wtap *wth, const char *line, char *cap_int, gboolean *cap_dir,
-    union wtap_pseudo_header *pseudo_header _U_, int *err, gchar **err_info)
+parse_netscreen_rec_hdr(wtap *wth, const char *line, char *cap_int,
+    gboolean *cap_dir, char *cap_dst, union wtap_pseudo_header *pseudo_header _U_,
+    int *err, gchar **err_info)
 {
        int     sec;
        int     dsec, pkt_len;
        char    direction[2];
+       char    cap_src[13];
 
-       if (sscanf(line, "%d.%d: %[a-z0-9/](%[io]) len=%d:",
-                  &sec, &dsec, cap_int, direction, &pkt_len) != 5) {
+       if (sscanf(line, "%9d.%9d: %15[a-z0-9/:.](%1[io]) len=%9d:%12s->%12s/",
+                  &sec, &dsec, cap_int, direction, &pkt_len, cap_src, cap_dst) < 5) {
                *err = WTAP_ERR_BAD_RECORD;
                *err_info = g_strdup("netscreen: Can't parse packet-header");
                return -1;