file_read() can return -1; don't just blindly add it to a previous
[obnox/wireshark/wip.git] / wiretap / snoop.c
index 1c0125c159c888e9c423b4eb6c689ac1d4f71427..89cc8a5f8a8cc5e41e71757f197d1136eba8be6e 100644 (file)
@@ -89,14 +89,17 @@ struct shomiti_trailer {
 #define RX_STATUS_TRIGGERED            0x0001  /* frame did trigger */
 
 static gboolean snoop_read(wtap *wth, int *err, gchar **err_info,
-    long *data_offset);
-static gboolean snoop_seek_read(wtap *wth, long seek_off,
+    gint64 *data_offset);
+static gboolean snoop_seek_read(wtap *wth, gint64 seek_off,
     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
     int *err, gchar **err_info);
 static gboolean snoop_read_atm_pseudoheader(FILE_T fh,
-    union wtap_pseudo_header *pseudo_header, int *err);
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
+static gboolean snoop_read_shomiti_wireless_pseudoheader(FILE_T fh,
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info,
+    int *header_size);
 static gboolean snoop_read_rec_data(FILE_T fh, guchar *pd, int length,
-    int *err);
+    int *err, gchar **err_info);
 static gboolean snoop_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
 
@@ -210,6 +213,18 @@ int snoop_open(wtap *wth, int *err, gchar **err_info)
                WTAP_ENCAP_UNKNOWN,     /* 100BaseT (but that's just Ethernet) */
        };
        #define NUM_SNOOP_ENCAPS (sizeof snoop_encap / sizeof snoop_encap[0])
+       #define SNOOP_PRIVATE_BIT 0x80000000
+       static const int snoop_private_encap[] = {
+               WTAP_ENCAP_UNKNOWN,     /* Not Used */
+               WTAP_ENCAP_UNKNOWN,     /* IPv4 Tunnel Link */
+               WTAP_ENCAP_UNKNOWN,     /* IPv6 Tunnel Link */
+               WTAP_ENCAP_UNKNOWN,     /* Virtual network interface */
+               WTAP_ENCAP_UNKNOWN,     /* IEEE 802.11 */
+               WTAP_ENCAP_IPNET,       /* ipnet(7D) link */
+               WTAP_ENCAP_UNKNOWN,     /* IPMP stub interface */
+               WTAP_ENCAP_UNKNOWN,     /* 6to4 Tunnel Link */
+       };
+       #define NUM_SNOOP_PRIVATE_ENCAPS (sizeof snoop_private_encap / sizeof snoop_private_encap[0])
        static const int shomiti_encap[] = {
                WTAP_ENCAP_ETHERNET,    /* IEEE 802.3 */
                WTAP_ENCAP_UNKNOWN,     /* IEEE 802.4 Token Bus */
@@ -226,15 +241,19 @@ int snoop_open(wtap *wth, int *err, gchar **err_info)
                WTAP_ENCAP_ETHERNET,    /* Gigabit Ethernet */
                WTAP_ENCAP_TOKEN_RING,  /* "IEEE 802.5 Shomiti" */
                WTAP_ENCAP_TOKEN_RING,  /* "4MB IEEE 802.5 Shomiti" */
+               WTAP_ENCAP_UNKNOWN,     /* Other */
+               WTAP_ENCAP_UNKNOWN,     /* Other */
+               WTAP_ENCAP_UNKNOWN,     /* Other */
+               WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
        };
        #define NUM_SHOMITI_ENCAPS (sizeof shomiti_encap / sizeof shomiti_encap[0])
        int file_encap;
 
        /* Read in the string that should be at the start of a "snoop" file */
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
+       bytes_read = file_read(magic, sizeof magic, wth->fh);
        if (bytes_read != sizeof magic) {
-               *err = file_error(wth->fh);
+               *err = file_error(wth->fh, err_info);
                if (*err != 0)
                        return -1;
                return 0;
@@ -247,9 +266,9 @@ int snoop_open(wtap *wth, int *err, gchar **err_info)
 
        /* Read the rest of the header. */
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
+       bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
        if (bytes_read != sizeof hdr) {
-               *err = file_error(wth->fh);
+               *err = file_error(wth->fh, err_info);
                if (*err != 0)
                        return -1;
                return 0;
@@ -308,9 +327,9 @@ int snoop_open(wtap *wth, int *err, gchar **err_info)
 
        /* Read first record header. */
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&rec_hdr, 1, sizeof rec_hdr, wth->fh);
+       bytes_read = file_read(&rec_hdr, sizeof rec_hdr, wth->fh);
        if (bytes_read != sizeof rec_hdr) {
-               *err = file_error(wth->fh);
+               *err = file_error(wth->fh, err_info);
                if (*err == 0 && bytes_read != 0)
                        *err = WTAP_ERR_SHORT_READ;
                if (*err != 0) {
@@ -346,7 +365,7 @@ int snoop_open(wtap *wth, int *err, gchar **err_info)
                         * Well, we have padding; how much?
                         */
                        padbytes = g_ntohl(rec_hdr.rec_len) -
-                           (sizeof rec_hdr + g_ntohl(rec_hdr.incl_len));
+                           ((guint)sizeof rec_hdr + g_ntohl(rec_hdr.incl_len));
 
                        /*
                         * Is it at least the size of a Shomiti trailer?
@@ -375,6 +394,18 @@ int snoop_open(wtap *wth, int *err, gchar **err_info)
 
                /* This is a Shomiti file */
                wth->file_type = WTAP_FILE_SHOMITI;
+       } else if (hdr.network & SNOOP_PRIVATE_BIT) {
+               if ((hdr.network^SNOOP_PRIVATE_BIT) >= NUM_SNOOP_PRIVATE_ENCAPS
+                   || snoop_private_encap[hdr.network^SNOOP_PRIVATE_BIT] == WTAP_ENCAP_UNKNOWN) {
+                       *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+                       *err_info = g_strdup_printf("snoop: private network type %u unknown or unsupported",
+                           hdr.network);
+                       return -1;
+               }
+               file_encap = snoop_private_encap[hdr.network^SNOOP_PRIVATE_BIT];
+
+               /* This is a snoop file */
+               wth->file_type = WTAP_FILE_SNOOP;
        } else {
                if (hdr.network >= NUM_SNOOP_ENCAPS
                    || snoop_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
@@ -402,9 +433,21 @@ int snoop_open(wtap *wth, int *err, gchar **err_info)
        return 1;
 }
 
+typedef struct {
+       guint8 pad[4];
+       guint8 undecrypt[2];
+       guint8 rate;
+       guint8 preamble;
+       guint8 code;
+       guint8 signal;
+       guint8 qual;
+       guint8 channel;
+} shomiti_wireless_header;
+
+
 /* Read the next packet */
 static gboolean snoop_read(wtap *wth, int *err, gchar **err_info,
-    long *data_offset)
+    gint64 *data_offset)
 {
        guint32 rec_size;
        guint32 packet_size;
@@ -414,12 +457,13 @@ static gboolean snoop_read(wtap *wth, int *err, gchar **err_info,
        char    padbuf[4];
        guint   padbytes;
        int     bytes_to_read;
+       int header_size;
 
        /* Read record header. */
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
+       bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
        if (bytes_read != sizeof hdr) {
-               *err = file_error(wth->fh);
+               *err = file_error(wth->fh, err_info);
                if (*err == 0 && bytes_read != 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -466,20 +510,20 @@ static gboolean snoop_read(wtap *wth, int *err, gchar **err_info,
                         * have a pseudo-header.
                         */
                        *err = WTAP_ERR_BAD_RECORD;
-                       *err_info = g_strdup_printf("snoop: atmsnoop file has a %u-byte packet, too small to have even an ATM pseudo-header\n",
+                       *err_info = g_strdup_printf("snoop: atmsnoop file has a %u-byte packet, too small to have even an ATM pseudo-header",
                            packet_size);
                        return FALSE;
                }
                if (!snoop_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
-                   err))
+                   err, err_info))
                        return FALSE;   /* Read error */
 
                /*
                 * Don't count the pseudo-header as part of the packet.
                 */
-               rec_size -= sizeof (struct snoop_atm_hdr);
-               orig_size -= sizeof (struct snoop_atm_hdr);
-               packet_size -= sizeof (struct snoop_atm_hdr);
+               rec_size -= (guint32)sizeof (struct snoop_atm_hdr);
+               orig_size -= (guint32)sizeof (struct snoop_atm_hdr);
+               packet_size -= (guint32)sizeof (struct snoop_atm_hdr);
                wth->data_offset += sizeof (struct snoop_atm_hdr);
                break;
 
@@ -494,11 +538,35 @@ static gboolean snoop_read(wtap *wth, int *err, gchar **err_info,
                else
                        wth->pseudo_header.eth.fcs_len = 0;
                break;
+
+       case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
+               if (packet_size < sizeof (shomiti_wireless_header)) {
+                       /*
+                        * Uh-oh, the packet isn't big enough to even
+                        * have a pseudo-header.
+                        */
+                       *err = WTAP_ERR_BAD_RECORD;
+                       *err_info = g_strdup_printf("snoop: Shomiti wireless file has a %u-byte packet, too small to have even a wireless pseudo-header",
+                           packet_size);
+                       return FALSE;
+               }
+               if (!snoop_read_shomiti_wireless_pseudoheader(wth->fh,
+                   &wth->pseudo_header, err, err_info, &header_size))
+                       return FALSE;   /* Read error */
+
+               /*
+                * Don't count the pseudo-header as part of the packet.
+                */
+               rec_size -= header_size;
+               orig_size -= header_size;
+               packet_size -= header_size;
+               wth->data_offset += header_size;
+               break;
        }
 
        buffer_assure_space(wth->frame_buffer, packet_size);
        if (!snoop_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
-           packet_size, err))
+           packet_size, err, err_info))
                return FALSE;   /* Read error */
        wth->data_offset += packet_size;
 
@@ -533,15 +601,15 @@ static gboolean snoop_read(wtap *wth, int *err, gchar **err_info,
                    rec_size, packet_size);
                return FALSE;
        }
-       padbytes = rec_size - (sizeof hdr + packet_size);
+       padbytes = rec_size - ((guint)sizeof hdr + packet_size);
        while (padbytes != 0) {
                bytes_to_read = padbytes;
                if ((unsigned)bytes_to_read > sizeof padbuf)
                        bytes_to_read = sizeof padbuf;
                errno = WTAP_ERR_CANT_READ;
-               bytes_read = file_read(padbuf, 1, bytes_to_read, wth->fh);
+               bytes_read = file_read(padbuf, bytes_to_read, wth->fh);
                if (bytes_read != bytes_to_read) {
-                       *err = file_error(wth->fh);
+                       *err = file_error(wth->fh, err_info);
                        if (*err == 0)
                                *err = WTAP_ERR_SHORT_READ;
                        return FALSE;
@@ -554,9 +622,9 @@ static gboolean snoop_read(wtap *wth, int *err, gchar **err_info,
 }
 
 static gboolean
-snoop_seek_read(wtap *wth, long seek_off,
+snoop_seek_read(wtap *wth, gint64 seek_off,
     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
-    int *err, gchar **err_info _U_)
+    int *err, gchar **err_info)
 {
        if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
                return FALSE;
@@ -565,7 +633,7 @@ snoop_seek_read(wtap *wth, long seek_off,
 
        case WTAP_ENCAP_ATM_PDUS:
                if (!snoop_read_atm_pseudoheader(wth->random_fh, pseudo_header,
-                   err)) {
+                   err, err_info)) {
                        /* Read error */
                        return FALSE;
                }
@@ -582,12 +650,20 @@ snoop_seek_read(wtap *wth, long seek_off,
                else
                        pseudo_header->eth.fcs_len = 0;
                break;
+
+       case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
+               if (!snoop_read_shomiti_wireless_pseudoheader(wth->random_fh,
+                   pseudo_header, err, err_info, NULL)) {
+                       /* Read error */
+                       return FALSE;
+               }
+               break;
        }
 
        /*
         * Read the packet data.
         */
-       if (!snoop_read_rec_data(wth->random_fh, pd, length, err))
+       if (!snoop_read_rec_data(wth->random_fh, pd, length, err, err_info))
                return FALSE;   /* failed */
 
        /*
@@ -602,7 +678,7 @@ snoop_seek_read(wtap *wth, long seek_off,
 
 static gboolean
 snoop_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
-    int *err)
+    int *err, gchar **err_info)
 {
        struct snoop_atm_hdr atm_phdr;
        int     bytes_read;
@@ -610,9 +686,9 @@ snoop_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
        guint16 vci;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(&atm_phdr, 1, sizeof (struct snoop_atm_hdr), fh);
+       bytes_read = file_read(&atm_phdr, sizeof (struct snoop_atm_hdr), fh);
        if (bytes_read != sizeof (struct snoop_atm_hdr)) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -694,15 +770,71 @@ snoop_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
 }
 
 static gboolean
-snoop_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
+snoop_read_shomiti_wireless_pseudoheader(FILE_T fh,
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info,
+    int *header_size)
 {
+       shomiti_wireless_header whdr;
        int     bytes_read;
+       int     rsize;
 
        errno = WTAP_ERR_CANT_READ;
-       bytes_read = file_read(pd, 1, length, fh);
+       bytes_read = file_read(&whdr, sizeof (shomiti_wireless_header), fh);
+       if (bytes_read != sizeof (shomiti_wireless_header)) {
+               *err = file_error(fh, err_info);
+               if (*err == 0)
+                       *err = WTAP_ERR_SHORT_READ;
+               return FALSE;
+       }
+
+       /* the 4th byte of the pad is actually a header length,
+        * we've already read 8 bytes of it, and it must never
+        * be less than 8.
+        *
+        * XXX - presumably that means that the header length
+        * doesn't include the length field, as we've read
+        * 12 bytes total.
+        *
+        * XXX - what's in the other 3 bytes of the padding?  Is it a
+        * 4-byte length field?
+        * XXX - is there anything in the rest of the header of interest?
+        * XXX - are there any files where the header is shorter than
+        * 4 bytes of length plus 8 bytes of information?
+        */
+       if (whdr.pad[3] < 8) {
+               *err = WTAP_ERR_BAD_RECORD;
+               *err_info = g_strdup_printf("snoop: Header length in Surveyor record is %u, less than minimum of 8",
+                   whdr.pad[3]);
+               return FALSE;
+       }
+       /* Skip the header. */
+       rsize = ((int) whdr.pad[3]) - 8;
+       if (file_seek(fh, rsize, SEEK_CUR, err) == -1)
+               return FALSE;
+
+       pseudo_header->ieee_802_11.fcs_len = 4;
+       pseudo_header->ieee_802_11.channel = whdr.channel;
+       pseudo_header->ieee_802_11.data_rate = whdr.rate;
+       pseudo_header->ieee_802_11.signal_level = whdr.signal;
+
+       /* add back the header and don't forget the pad as well */
+       if(header_size != NULL)
+           *header_size = rsize + 8 + 4;
+
+    return TRUE;
+}
+
+static gboolean
+snoop_read_rec_data(FILE_T fh, guchar *pd, int length, int *err,
+    gchar **err_info)
+{
+       int     bytes_read;
+
+       errno = WTAP_ERR_CANT_READ;
+       bytes_read = file_read(pd, length, fh);
 
        if (bytes_read != length) {
-               *err = file_error(fh);
+               *err = file_error(fh, err_info);
                if (*err == 0)
                        *err = WTAP_ERR_SHORT_READ;
                return FALSE;
@@ -744,36 +876,23 @@ int snoop_dump_can_write_encap(int encap)
 
 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
    failure */
-gboolean snoop_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
+gboolean snoop_dump_open(wtap_dumper *wdh, int *err)
 {
        struct snoop_hdr file_hdr;
-       size_t nwritten;
 
        /* This is a snoop file */
        wdh->subtype_write = snoop_dump;
        wdh->subtype_close = NULL;
 
        /* Write the file header. */
-       nwritten = fwrite(&snoop_magic, 1, sizeof snoop_magic, wdh->fh);
-       if (nwritten != sizeof snoop_magic) {
-               if (nwritten == 0 && ferror(wdh->fh))
-                       *err = errno;
-               else
-                       *err = WTAP_ERR_SHORT_WRITE;
+       if (!wtap_dump_file_write(wdh, &snoop_magic, sizeof snoop_magic, err))
                return FALSE;
-       }
 
        /* current "snoop" format is 2 */
        file_hdr.version = g_htonl(2);
        file_hdr.network = g_htonl(wtap_encap[wdh->encap]);
-       nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
-       if (nwritten != sizeof file_hdr) {
-               if (nwritten == 0 && ferror(wdh->fh))
-                       *err = errno;
-               else
-                       *err = WTAP_ERR_SHORT_WRITE;
+       if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
                return FALSE;
-       }
 
        return TRUE;
 }
@@ -786,7 +905,6 @@ static gboolean snoop_dump(wtap_dumper *wdh,
        const guchar *pd, int *err)
 {
        struct snooprec_hdr rec_hdr;
-       size_t nwritten;
        int reclen;
        guint padlen;
        static char zeroes[4];
@@ -799,7 +917,7 @@ static gboolean snoop_dump(wtap_dumper *wdh,
                atm_hdrsize = 0;
 
        /* Record length = header length plus data length... */
-       reclen = sizeof rec_hdr + phdr->caplen + atm_hdrsize;
+       reclen = (int)sizeof rec_hdr + phdr->caplen + atm_hdrsize;
 
        /* ... plus enough bytes to pad it to a 4-byte boundary. */
        padlen = ((reclen + 3) & ~3) - reclen;
@@ -811,14 +929,8 @@ static gboolean snoop_dump(wtap_dumper *wdh,
        rec_hdr.cum_drops = 0;
        rec_hdr.ts_sec = g_htonl(phdr->ts.secs);
        rec_hdr.ts_usec = g_htonl(phdr->ts.nsecs / 1000);
-       nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, wdh->fh);
-       if (nwritten != sizeof rec_hdr) {
-               if (nwritten == 0 && ferror(wdh->fh))
-                       *err = errno;
-               else
-                       *err = WTAP_ERR_SHORT_WRITE;
+       if (!wtap_dump_file_write(wdh, &rec_hdr, sizeof rec_hdr, err))
                return FALSE;
-       }
 
        if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
                /*
@@ -855,33 +967,15 @@ static gboolean snoop_dump(wtap_dumper *wdh,
                }
                atm_hdr.vpi = (guint8) pseudo_header->atm.vpi;
                atm_hdr.vci = g_htons(pseudo_header->atm.vci);
-               nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
-               if (nwritten != sizeof atm_hdr) {
-                       if (nwritten == 0 && ferror(wdh->fh))
-                               *err = errno;
-                       else
-                               *err = WTAP_ERR_SHORT_WRITE;
+               if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
                        return FALSE;
-               }
        }
 
-       nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
-       if (nwritten != phdr->caplen) {
-               if (nwritten == 0 && ferror(wdh->fh))
-                       *err = errno;
-               else
-                       *err = WTAP_ERR_SHORT_WRITE;
+       if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
                return FALSE;
-       }
 
        /* Now write the padding. */
-       nwritten = fwrite(zeroes, 1, padlen, wdh->fh);
-       if (nwritten != padlen) {
-               if (nwritten == 0 && ferror(wdh->fh))
-                       *err = errno;
-               else
-                       *err = WTAP_ERR_SHORT_WRITE;
+       if (!wtap_dump_file_write(wdh, zeroes, padlen, err))
                return FALSE;
-       }
        return TRUE;
 }