dhcp/dhcp4.cpp

119 lines
3.2 KiB
C++

#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <arpa/inet.h>
#include "dhcp4.h"
namespace dhcp4 {
int make_message(void * buf,
uint32_t bootp_message_type,
uint32_t transaction_id,
uint8_t const * chaddr,
uint32_t dhcp_message_type,
uint32_t requested_ip_address)
{
memset(buf, 0, (sizeof (message)));
message * msg = reinterpret_cast<message *>(buf);
msg->op = bootp_message_type;
msg->htype = htype::ethernet;
msg->hlen = 6;
msg->xid = htonl(transaction_id);
memcpy(msg->chaddr, chaddr, 6);
int index = 0;
uint8_t * cookie = &msg->options[index];
index += 4;
cookie[0] = 0x63;
cookie[1] = 0x82;
cookie[2] = 0x53;
cookie[3] = 0x63;
uint8_t * message_type = &msg->options[index];
index += 2 + 1;
message_type[0] = option::message_type;
message_type[1] = 1; // length
message_type[2] = dhcp_message_type;
{
uint8_t * prl = &msg->options[index];
int length = 3;
index += 2 + length;
prl[0] = option::parameter_request_list;
prl[1] = length;
prl[2] = option::subnet_mask;
prl[3] = option::router;
prl[4] = option::domain_name_server;
}
if (requested_ip_address != 0) {
uint8_t * addr = &msg->options[index];
int length = 4;
index += 2 + length;
addr[0] = option::requested_ip_address;
addr[1] = length;
memcpy(&addr[2], &requested_ip_address, 4);
}
uint8_t * end = &msg->options[index];
index += 1;
end[0] = 255;
return (sizeof (message)) + index;
}
char const * message_type_tostr(int message_type)
{
switch (message_type) {
case message_type::dhcpdiscover: return "dhcpdiscover";
case message_type::dhcpoffer: return "dhcpoffer";
case message_type::dhcprequest: return "dhcprequest";
case message_type::dhcpdecline: return "dhcpdecline";
case message_type::dhcpack: return "dhcpack";
case message_type::dhcpnak: return "dhcpnak";
case message_type::dhcprelease: return "dhcprelease";
case message_type::dhcpinform: return "dhcpinform";
default:
assert(false);
return nullptr;
}
}
void parse_options(message const * m, int options_length, options * o)
{
uint8_t const * options = m->options;
int index = 4;
while (index + 2 <= options_length) {
int option = options[index + 0];
int option_length = options[index + 1];
//printf("option %d length %d\n", option, option_length);
switch (option) {
case option::message_type:
o->message_type = options[index + 2];
break;
case option::subnet_mask:
o->subnet_mask = *reinterpret_cast<uint32_t const *>(&options[index + 2]);
break;
case option::router:
o->router = *reinterpret_cast<uint32_t const *>(&options[index + 2]);
break;
case option::domain_name_server:
o->domain_name_server = *reinterpret_cast<uint32_t const *>(&options[index + 2]);
break;
default:
break;
}
index += 2 + option_length;
}
assert(options[index] == 255);
}
}