
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pcap/pcap.h>

#include "raw_socket.h"
#include "packet_construct.h"

void raw_socket_destory(struct raw_socket *raw)
{
    if (raw)
    {
        if (raw->sockfd)
        {
            close(raw->sockfd);
        }
        free(raw);
        raw = NULL;
    }
}

struct raw_socket *raw_socket_create(const char *interface, int fd_so_mask)
{
    struct ifreq ifr = {0};

    struct raw_socket *raw = (struct raw_socket *)calloc(1, sizeof(struct raw_socket));
    memcpy(raw->interface, interface, strlen(interface));

    raw->sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (raw->sockfd < 0)
    {
        printf("socket() failed, (%d: %s)", errno, strerror(errno));
        goto error;
    }

    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", raw->interface);
    if (ioctl(raw->sockfd, SIOCGIFHWADDR, &ifr) < 0)
    {
        printf("ioctl(SIOCGIFHWADDR) failed, (%d: %s)", errno, strerror(errno));
        goto error;
    }
    memcpy(&(raw->mac_addr), ifr.ifr_hwaddr.sa_data, 6);

    raw->sockaddr.sll_ifindex = if_nametoindex(interface);
    if (raw->sockaddr.sll_ifindex == 0)
    {
        printf("if_nametoindex() failed, (%d: %s)", errno, strerror(errno));
        goto error;
    }
    raw->sockaddr.sll_family = AF_PACKET;
    memcpy((void *)&(raw->sockaddr.sll_addr), (void *)&(raw->mac_addr), 6);
    raw->sockaddr.sll_halen = 6;

    if (setsockopt(raw->sockfd, SOL_SOCKET, SO_MARK, (char *)&fd_so_mask, sizeof(fd_so_mask)) < 0)
    {
        printf("setsockopt(SO_MARK) failed, (%d: %s)", errno, strerror(errno));
        goto error;
    }

    return raw;

error:
    raw_socket_destory(raw);

    return NULL;
}

int raw_socket_send(struct raw_socket *raw, const char *data, int data_len)
{
    int ret = sendto(raw->sockfd, data, data_len, 0, (struct sockaddr *)&raw->sockaddr, sizeof(raw->sockaddr));
    if (ret < 0)
    {
        printf("sendto() failed, (%d: %s)", errno, strerror(errno));
    }

    return ret;
}

int raw_socket_recv(struct raw_socket *raw, char *buff, int buff_size)
{
    socklen_t addr_len = sizeof(raw->sockaddr);
    int ret = recvfrom(raw->sockfd, buff, buff_size, 0, (struct sockaddr *)&raw->sockaddr, &addr_len);
    if (ret < 0)
    {
        printf("sendto() failed, (%d: %s)", errno, strerror(errno));
    }

    return ret;
}