/*-
 * Copyright (c) 2005 Robert N. M. Watson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Simple library for dealing with packet-like memory handling.  Packet data
 * structures own a buffer with a copy of the packet data, have an iterator
 * for moving through the data, and store libpcap capture information in an
 * optional field.  Parse routines generally wrap around packet_get_data(),
 * which handles short reads and updating the iterator.  In general, these
 * routines and their wrappers do not validate data, they just extract it in
 * the right quantity and data type.  Pointers to within the private buffer
 * are not returned, only copies to caller-owned memory.
 */

#include <sys/types.h>

#include <pcap.h>
#include <stdlib.h>
#include <string.h>

#include "queue.h"
#include "packet.h"

struct packet *
packet_new_pkthdr(int len, const void *data, const struct pcap_pkthdr *pkthdr)
{
	struct packet *p;

	p = malloc(sizeof(*p));
	if (p == NULL)
		return (NULL);
	bzero(p, sizeof(*p));

	p->p_data = malloc(len);
	if (p->p_data == NULL) {
		free(p);
		return (NULL);
	}
	p->p_len = len;
	memcpy(p->p_data, data, len);
	p->p_ptr = p->p_data;
	if (pkthdr != NULL)
		p->p_pkthdr = *pkthdr;
	return (p);
}

struct packet *
packet_new(int len, const void *data)
{

	return (packet_new_pkthdr(len, data, NULL));
}

void
packet_free(struct packet *p)
{

	free(p->p_data);
	memset(p, 0, sizeof(*p));
	free(p);
}

int
packet_get_data(struct packet *p, int len, void *data)
{

	if (p->p_ptr + len > p->p_data + p->p_len)
		return (-1);
	memcpy(data, p->p_ptr, len);
	p->p_ptr += len;
	return (0);
}

int
packet_get_int8(struct packet *p, int8_t *int8)
{

	return (packet_get_data(p, sizeof(int8), int8));
}

int
packet_get_uint8(struct packet *p, u_int8_t *uint8)
{

	return (packet_get_data(p, sizeof(uint8), uint8));
}

int
packet_get_uint16(struct packet *p, u_int16_t *uint16)
{

	return (packet_get_data(p, sizeof(uint16), uint16));
}

int
packet_get_uint32(struct packet *p, u_int32_t *uint32)
{

	return (packet_get_data(p, sizeof(uint32), uint32));
}

int
packet_get_uint64(struct packet *p, u_int64_t *uint64)
{

	return (packet_get_data(p, sizeof(uint64), uint64));
}

int
packet_skip_data(struct packet *p, int len)
{

	if (p->p_ptr + len > p->p_data + p->p_len)
		return (-1);
	p->p_ptr += len;
	return (0);
}

/*
 * Take a region of the current packet and return a new packet holding that
 * region in fresh memory.  Does not increment the current pointer.
 *
 * XXXRW: Should it increment the current pointer?  Probably.
 */
struct packet *
packet_get_subpacket(struct packet *p, int len)
{
	struct packet *rp;

	if (p->p_ptr + len > p->p_data + p->p_len)
		return (NULL);

	rp = packet_new(len, p->p_ptr);
	if (rp == NULL)
		return (NULL);

	return (rp);
}
