114 lines
2.8 KiB
C

//
// Created by epagris on 2022.12.09..
//
#include <stdlib.h>
#include "dhcp.h"
#include "../../dynmem.h"
#include "../../utils.h"
#include "../../connection_block.h"
#include "../conn_blocks/udp_connblock.h"
static struct {
DhcpState state;
void * buf;
ConnBlock connb;
uint32_t tranId;
} s;
static const uint8_t DHCP_MAGIC_COOKIE[] = { 99, 130, 83, 99 };
#define SNAME_LEN (64)
#define FILE_LEN (128)
// (Exact copy of the standard.)
typedef enum {
DHCPDISCOVER = 1,
DHCPOFFER = 2,
DHCPREQUEST = 3,
DHCPDECLINE = 4,
DHCPACK = 5,
DHCPNAK = 6,
DHCPRELEASE = 7
} DhcpMsgType;
static void dhcp_option_insert_msg_type(uint8_t ** bufPtr, int msgType) {
(*bufPtr)[0] = 0x35;
(*bufPtr)[1] = 1;
(*bufPtr)[2] = msgType;
(*bufPtr) += 3;
}
static void dhcp_option_insert_max_msg_size(uint8_t ** bufPtr, uint16_t maxSize) {
(*bufPtr)[0] = 0x39;
(*bufPtr)[1] = 2;
(*bufPtr)[2] = (maxSize >> 8) & 0xFF;
(*bufPtr)[3] = maxSize & 0xFF;
(*bufPtr) += 4;
}
static void dhcp_option_insert_end(uint8_t ** bufPtr) {
(*bufPtr)[0] = 0xFF;
(*bufPtr) += 1;
}
static void dhcp_send(EthInterface * intf, DhcpOps * ops) {
// construct message
uint8_t * buf = (uint8_t *)s.buf;
memset(buf, 0, DHCP_MIN_PACKET_SIZE);
FILL_BYTE_ADVANCE(buf, &(ops->op));
FILL_BYTE_ADVANCE(buf, &(ops->htype));
FILL_BYTE_ADVANCE(buf, &(ops->hlen));
FILL_BYTE_ADVANCE(buf, &(ops->hops));
FILL_DWORD_H2N_ADVANCE(buf, ops->xid);
FILL_WORD_H2N_ADVANCE(buf, ops->secs);
FILL_WORD_H2N_ADVANCE(buf, ops->flags);
FILL_DWORD_H2N_ADVANCE(buf, ops->ciaddr);
FILL_DWORD_H2N_ADVANCE(buf, ops->yiaddr);
FILL_DWORD_H2N_ADVANCE(buf, ops->siaddr);
FILL_DWORD_H2N_ADVANCE(buf, ops->giaddr);
FILL_ADVANCE(buf, ops->chaddr, 16);
buf += SNAME_LEN + FILE_LEN;
FILL_ADVANCE(buf, DHCP_MAGIC_COOKIE, 4); // DHCP magic cookie
// insert options
dhcp_option_insert_msg_type(&buf, DHCPDISCOVER);
dhcp_option_insert_max_msg_size(&buf, 1500);
dhcp_option_insert_end(&buf);
udp_sendto(&s.connb, s.buf, DHCP_MIN_PACKET_SIZE, IPv4_ANY_ADDR, DHCP_SERVER_PORT);
}
static void dhcp_discover(EthInterface * intf) {
s.tranId = rand();
DhcpOps ops = { 0 };
ops.op = DHCP_BOOTREQUEST;
ops.htype = 1;
ops.hlen = 6;
ops.hops = 0;
ops.xid = s.tranId;
ops.secs = 0;
ops.flags = 0;
ops.ciaddr = 0;
ops.yiaddr = 0;
ops.siaddr = 0;
ops.giaddr = 0;
memcpy(ops.chaddr, intf->mac, ETH_HW_ADDR_LEN);
dhcp_send(intf, &ops);
}
static int dhcp_resp_cb(const Pckt * pckt) {
return 0;
}
void dhcp_initiate(EthInterface *intf) {
s.state = DHCP_INIT_REBOOT;
s.buf = dynmem_alloc(DHCP_MIN_PACKET_SIZE);
s.connb = udp_new_connblock(intf, IPv4_ANY_ADDR, DHCP_CLIENT_PORT, dhcp_resp_cb);
dhcp_discover(intf);
}