#include <stdio.h>
#include <arpa/inet.h>
#include "main.h"

void skb_new(struct sk_buff *skb, uint8_t *buffer, size_t len)
{
    skb->head = buffer;
    skb->data = buffer + len;
    skb->len = 0;
}

void skb_load(struct sk_buff *skb, uint8_t *buffer, size_t len)
{
    skb->head = buffer;
    skb->data = buffer;
    skb->len = len;
}

size_t skb_headroom(struct sk_buff *skb)
{
    return skb->data - skb->head;
}

uint8_t *skb_push(struct sk_buff *skb, size_t len)
{
    assert(skb_headroom(skb) >= len);

    skb->data -= len;
    skb->len += len;

    return skb->data;
}

void skb_push_u8(struct sk_buff *skb, uint8_t value)
{
    uint8_t *buffer = skb_push(skb, sizeof(value));
    *buffer = value;
}

void skb_push_u16(struct sk_buff *skb, uint16_t value)
{
    uint16_t *buffer = (uint16_t *)skb_push(skb, sizeof(value));
    *buffer = htons(value);
}

void skb_push_u32(struct sk_buff *skb, uint32_t value)
{
    uint32_t *buffer = (uint32_t *)skb_push(skb, sizeof(value));
    *buffer = htonl(value);
}

int pskb_may_pull(struct sk_buff *skb, size_t len)
{
    return len <= skb->len;
}

uint8_t *skb_pull(struct sk_buff *skb, size_t len)
{
    assert(pskb_may_pull(skb, len));

    skb->data += len;
    skb->len -= len;

    return skb->data;
}

uint8_t skb_pull_u8(struct sk_buff *skb)
{
    uint8_t *buffer = skb->data;
    skb_pull(skb, sizeof(*buffer));
    return *buffer;
}

uint16_t skb_pull_u16(struct sk_buff *skb)
{
    uint16_t *buffer = (uint16_t *)skb->data;
    skb_pull(skb, sizeof(*buffer));
    return ntohs(*buffer);
}

uint32_t skb_pull_u32(struct sk_buff *skb)
{
    uint32_t *buffer = (uint32_t *)skb->data;
    skb_pull(skb, sizeof(*buffer));
    return ntohl(*buffer);
}

void skb_print(FILE *file, struct sk_buff *skb)
{
    skb_print_part(file, skb, skb->len, 8, 16);
}

void skb_print_part(FILE *file, struct sk_buff *skb, size_t bytes, size_t bytes_per_block, size_t blocks_per_line)
{
    size_t i;
    size_t bytes_per_line = bytes_per_block * blocks_per_line;

    fprintf(file, "packet %p headroom=%zu, len=%zu", (void*)skb, skb_headroom(skb), skb->len);

    for (i = 0; i < skb->len && i < bytes; ++i) {
        if (i % bytes_per_line == 0) {
            fprintf(file, "\n");
        } else if (i % bytes_per_block == 0) {
            fprintf(file, " ");
        }
        fprintf(file, "%02x ", skb->data[i]);
    }

    if (bytes < skb->len) {
       fprintf(file, "...");
    }
    fprintf(file, "\n");
}

