예제 #1
0
/*
 * 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++;
		}
	}
}
예제 #2
0
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);
}
예제 #4
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);
}