/* * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host * byte order when capturing (it's supplied directly from a * memory-mapped buffer shared by the kernel). * * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED capture file, * we need to convert it from the byte order of the host that wrote * the file to this host's byte order. */ static void swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, int header_len_64_bytes) { pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf; bpf_u_int32 offset = 0; usb_isodesc *pisodesc; int32_t numdesc, i; /* * "offset" is the offset *past* the field we're swapping; * we skip the field *before* checking to make sure * the captured data length includes the entire field. */ /* * The URB id is a totally opaque value; do we really need to * convert it to the reading host's byte order??? */ offset += 8; /* skip past id */ if (hdr->caplen < offset) return; uhdr->id = SWAPLL(uhdr->id); offset += 4; /* skip past various 1-byte fields */ offset += 2; /* skip past bus_id */ if (hdr->caplen < offset) return; uhdr->bus_id = SWAPSHORT(uhdr->bus_id); offset += 2; /* skip past various 1-byte fields */ offset += 8; /* skip past ts_sec */ if (hdr->caplen < offset) return; uhdr->ts_sec = SWAPLL(uhdr->ts_sec); offset += 4; /* skip past ts_usec */ if (hdr->caplen < offset) return; uhdr->ts_usec = SWAPLONG(uhdr->ts_usec); offset += 4; /* skip past status */ if (hdr->caplen < offset) return; uhdr->status = SWAPLONG(uhdr->status); offset += 4; /* skip past urb_len */ if (hdr->caplen < offset) return; uhdr->urb_len = SWAPLONG(uhdr->urb_len); offset += 4; /* skip past data_len */ if (hdr->caplen < offset) return; uhdr->data_len = SWAPLONG(uhdr->data_len); if (uhdr->transfer_type == URB_ISOCHRONOUS) { offset += 4; /* skip past s.iso.error_count */ if (hdr->caplen < offset) return; uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count); offset += 4; /* skip past s.iso.numdesc */ if (hdr->caplen < offset) return; uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc); } else offset += 8; /* skip USB setup header */ if (header_len_64_bytes) { /* * This is either the "version 1" header, with * 16 bytes of additional fields at the end, or * a "version 0" header from a memory-mapped * capture, with 16 bytes of zeroed-out padding * at the end. Byte swap them as if this were * a "version 1" header. */ offset += 4; /* skip past interval */ if (hdr->caplen < offset) return; uhdr->interval = SWAPLONG(uhdr->interval); offset += 4; /* skip past start_frame */ if (hdr->caplen < offset) return; uhdr->start_frame = SWAPLONG(uhdr->start_frame); offset += 4; /* skip past xfer_flags */ if (hdr->caplen < offset) return; uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags); offset += 4; /* skip past ndesc */ if (hdr->caplen < offset) return; uhdr->ndesc = SWAPLONG(uhdr->ndesc); } if (uhdr->transfer_type == URB_ISOCHRONOUS) { /* swap the values in struct linux_usb_isodesc */ pisodesc = (usb_isodesc *)(void *)(buf+offset); numdesc = uhdr->s.iso.numdesc; for (i = 0; i < numdesc; i++) { offset += 4; /* skip past status */ if (hdr->caplen < offset) return; pisodesc->status = SWAPLONG(pisodesc->status); offset += 4; /* skip past offset */ if (hdr->caplen < offset) return; pisodesc->offset = SWAPLONG(pisodesc->offset); offset += 4; /* skip past len */ if (hdr->caplen < offset) return; pisodesc->len = SWAPLONG(pisodesc->len); offset += 4; /* skip past padding */ pisodesc++; } } }
static int process_idb_options(pcap_t *p, struct pcapng_interface_description_fields *idbp, struct block_cursor *cursor, u_int *tsresol, u_int64_t *tsoffset, char *errbuf) { struct pcapng_option_header opthdr; void *optvalue; int saw_tsresol, saw_tsoffset, saw_ifname; u_char tsresol_opt; u_int i; saw_tsresol = 0; saw_tsoffset = 0; saw_ifname = 0; while (cursor->data_remaining != 0) { /* * Get the option header. */ if (get_opthdr_from_block_data(&opthdr, p->sf.swapped, cursor, errbuf) == NULL) { /* * Option header is cut short. */ goto fail; /* error */ } /* * Get option value. */ optvalue = get_optvalue_from_block_data(cursor, &opthdr, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ goto fail; /* error */ } switch (opthdr.option_code) { case PCAPNG_IF_NAME: if (saw_ifname) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_name option"); goto fail; /* error */ } saw_ifname = 1; break; case PCAPNG_OPT_ENDOFOPT: if (opthdr.option_length != 0) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr.option_length); goto fail; /* error */ } goto done; case PCAPNG_IF_TSRESOL: if (opthdr.option_length != 1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsresol option with length %u != 1", opthdr.option_length); goto fail; /* error */ } if (saw_tsresol) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsresol option"); goto fail; /* error */ } saw_tsresol = 1; tsresol_opt = *(u_int *)optvalue; if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ *tsresol = 1 << (tsresol_opt & 0x7F); } else { /* * Resolution is negative power of 10. */ *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } if (*tsresol == 0) { /* * Resolution is too high. */ if (tsresol_opt & 0x80) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 2^-%u is too high", tsresol_opt & 0x7F); } else { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); } goto fail; /* error */ } break; case PCAPNG_IF_TSOFFSET: if (opthdr.option_length != 8) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsoffset option with length %u != 8", opthdr.option_length); goto fail; /* error */ } if (saw_tsoffset) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsoffset option"); goto fail; /* error */ } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); if (p->sf.swapped) *tsoffset = SWAPLL(*tsoffset); break; default: break; } } done: /* * Count this interface. */ p->ifcount++; /* * Compute the scaling factor to convert the * sub-second part of the time stamp to * microseconds. */ if (p->sf.tsresol > 1000000) { /* * Higher than microsecond resolution; * scale down to microseconds. */ p->sf.tsscale = (p->sf.tsresol / 1000000); } else { /* * Lower than microsecond resolution; * scale up to microseconds. */ p->sf.tsscale = (1000000 / p->sf.tsresol); } return (0); fail: return (-1); }
static int process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, u_int64_t *tsoffset, char *errbuf) { struct option_header *opthdr; void *optvalue; int saw_tsresol, saw_tsoffset; u_char tsresol_opt; u_int i; saw_tsresol = 0; saw_tsoffset = 0; while (cursor->data_remaining != 0) { /* * Get the option header. */ opthdr = get_opthdr_from_block_data(p, cursor, errbuf); if (opthdr == NULL) { /* * Option header is cut short. */ return (-1); } /* * Get option value. */ optvalue = get_optvalue_from_block_data(cursor, opthdr, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ return (-1); } switch (opthdr->option_code) { case OPT_ENDOFOPT: if (opthdr->option_length != 0) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr->option_length); return (-1); } goto done; case IF_TSRESOL: if (opthdr->option_length != 1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsresol option with length %u != 1", opthdr->option_length); return (-1); } if (saw_tsresol) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsresol option"); return (-1); } saw_tsresol = 1; memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ *tsresol = 1 << (tsresol_opt & 0x7F); } else { /* * Resolution is negative power of 10. */ *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } if (*tsresol == 0) { /* * Resolution is too high. */ if (tsresol_opt & 0x80) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 2^-%u is too high", tsresol_opt & 0x7F); } else { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); } return (-1); } break; case IF_TSOFFSET: if (opthdr->option_length != 8) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsoffset option with length %u != 8", opthdr->option_length); return (-1); } if (saw_tsoffset) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsoffset option"); return (-1); } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); if (p->swapped) *tsoffset = (uint64_t)SWAPLL(*tsoffset); break; default: break; } } done: return (0); }
static int process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol, uint64_t *tsoffset, int *is_binary, char *errbuf) { struct option_header *opthdr; void *optvalue; int saw_tsresol, saw_tsoffset; uint8_t tsresol_opt; u_int i; saw_tsresol = 0; saw_tsoffset = 0; while (cursor->data_remaining != 0) { /* * Get the option header. */ opthdr = get_opthdr_from_block_data(p, cursor, errbuf); if (opthdr == NULL) { /* * Option header is cut short. */ return (-1); } /* * Get option value. */ optvalue = get_optvalue_from_block_data(cursor, opthdr, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ return (-1); } switch (opthdr->option_code) { case OPT_ENDOFOPT: if (opthdr->option_length != 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr->option_length); return (-1); } goto done; case IF_TSRESOL: if (opthdr->option_length != 1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsresol option with length %u != 1", opthdr->option_length); return (-1); } if (saw_tsresol) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsresol option"); return (-1); } saw_tsresol = 1; memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ uint8_t tsresol_shift = (tsresol_opt & 0x7F); if (tsresol_shift > 63) { /* * Resolution is too high; 2^-{res} * won't fit in a 64-bit value. */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 2^-%u is too high", tsresol_shift); return (-1); } *is_binary = 1; *tsresol = ((uint64_t)1) << tsresol_shift; } else { /* * Resolution is negative power of 10. */ if (tsresol_opt > 19) { /* * Resolution is too high; 2^-{res} * won't fit in a 64-bit value (the * largest power of 10 that fits * in a 64-bit value is 10^19, as * the largest 64-bit unsigned * value is ~1.8*10^19). */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); return (-1); } *is_binary = 0; *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } break; case IF_TSOFFSET: if (opthdr->option_length != 8) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsoffset option with length %u != 8", opthdr->option_length); return (-1); } if (saw_tsoffset) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsoffset option"); return (-1); } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); if (p->swapped) *tsoffset = SWAPLL(*tsoffset); break; default: break; } } done: return (0); }