MES3.0はLinuxの下位互換性であり、MES3.0のユーザープログラムは原則としてLinuxでも同じソースコードで動作します。
以下、MES3.0で動作確認されたLinuxとソースコード互換のDHCPクライアントの例です。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/route.h>
#include "dhcp.h"
unsigned int DhcpServerIP; ///< IP address of the DHCP server that offered lease
unsigned int DhcpClientIP;
unsigned int DhcpNetmask;
unsigned int DhcpGatewayIP;
unsigned int DhcpDNSServerIP;
unsigned int DhcpTransactID; ///< Unique transaction ID that identifies DHCP request/replies
unsigned int DhcpLeaseTime; ///< Number of seconds left in DHCP lease
unsigned char macaddr[6];
//#define NET_DEBUG 3
static int ifup(char *dev, int ip, int mask) {
int sk, ret;
struct ifreq ifr;
struct sockaddr_in *s_in;
sk = socket(AF_INET, SOCK_DGRAM, 0);
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
ret = ioctl(sk, SIOCGIFFLAGS, &ifr);
if(ret == -1) return -1;
ifr.ifr_flags |= IFF_UP;
ioctl(sk, SIOCSIFFLAGS, &ifr);
s_in = (struct sockaddr_in *)&ifr.ifr_addr;
s_in->sin_family = AF_INET;
s_in->sin_addr.s_addr = htonl(ip);
ioctl(sk, SIOCSIFADDR, &ifr);
s_in->sin_addr.s_addr = htonl(mask);
ioctl(sk, SIOCSIFNETMASK, &ifr);
close(sk);
return 0;
}
static int dhcpIn(char *dev, int sock, int len, struct netDhcpHeader *packet) {
struct ifreq ifr;
struct sockaddr_in *s_in;
unsigned char msgtype;
unsigned char *optptr;
unsigned int val;
s_in = (struct sockaddr_in *)&ifr.ifr_addr;
#if NET_DEBUG >= 3
dhcpPrintHeader(packet);
#endif
// check that this is a reply, and for me
if(packet->bootp.op != BOOTP_OP_BOOTREPLY ||
packet->bootp.htype != BOOTP_HTYPE_ETHERNET ||
packet->bootp.hlen != BOOTP_HLEN_ETHERNET ||
be32toh(packet->cookie) != 0x63825363 ||
be32toh(packet->bootp.xid) != DhcpTransactID) return -1;
// process incoming packet
// check reply type
dhcpGetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &msgtype);
#if NET_DEBUG >= 2
printf("DHCP: Received msgtype = %d\n", msgtype);
#endif
if(msgtype == DHCP_MSG_DHCPOFFER) {
// get DHCP server ID
val = 0;
dhcpGetOption(packet->options, DHCP_OPT_SERVERID, 4, &val);
if(val == 0) {
val = packet->bootp.siaddr;
}
DhcpServerIP = be32toh(val);
DhcpGatewayIP = DhcpServerIP;
DhcpDNSServerIP = DhcpServerIP;
DhcpClientIP = be32toh(packet->bootp.yiaddr);
#ifdef NET_DEBUG
printf("DHCP: Got offer from server ");
val = DhcpServerIP;
printf("%d.%d.%d.%d\n", (val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
printf("DHCP: Sending request in response to offer\n");
#endif
// get netmask
val = 0;
dhcpGetOption(packet->options, DHCP_OPT_NETMASK, 4, &val);
DhcpNetmask = htobe32(val);
if(DhcpNetmask == 0) DhcpNetmask = 0xffffff00;
// get gateway
val = 0;
dhcpGetOption(packet->options, DHCP_OPT_ROUTERS, 4, &val);
if(val != 0) DhcpGatewayIP = htobe32(val);
// get gateway
val = 0;
dhcpGetOption(packet->options, DHCP_OPT_DNSSERVERS, 4, &val);
if(val != 0) DhcpDNSServerIP = htobe32(val);
} else if(msgtype == DHCP_MSG_DHCPACK) {
// get netmask
val = 0;
dhcpGetOption(packet->options, DHCP_OPT_NETMASK, 4, &val);
DhcpNetmask = htobe32(val);
if(DhcpNetmask == 0) DhcpNetmask = 0xffffff00;
// get gateway
val = 0;
dhcpGetOption(packet->options, DHCP_OPT_ROUTERS, 4, &val);
if(val != 0) DhcpGatewayIP = htobe32(val);
// get gateway
val = 0;
dhcpGetOption(packet->options, DHCP_OPT_DNSSERVERS, 4, &val);
if(val != 0) DhcpDNSServerIP = htobe32(val);
// get lease time
dhcpGetOption(packet->options, DHCP_OPT_LEASETIME, 4, &val);
DhcpLeaseTime = htobe32(val);
// assign new network info
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
s_in->sin_family = AF_INET;
s_in->sin_addr.s_addr = packet->bootp.yiaddr;
ioctl(sock, SIOCSIFADDR, &ifr);
s_in->sin_addr.s_addr = htonl(DhcpNetmask);
ioctl(sock, SIOCSIFNETMASK, &ifr);
ifup(dev, be32toh(packet->bootp.yiaddr), DhcpNetmask);
#ifdef NET_DEBUG
// print netmask
val = DhcpNetmask;
printf("Mask : %d.%d.%d.%d\n", (val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
// print gateway
val = DhcpGatewayIP;
printf("GW : %d.%d.%d.%d\n", (val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
// print dns server
val = DhcpDNSServerIP;
printf("DNS : %d.%d.%d.%d\n", (val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
printf("DHCP: Got request ACK, bind complete\n");
#endif
} else {
return -1;
}
return msgtype;
}
static int dhcpRequest(char *dev, int sock) {
struct ifreq ifr;
struct sockaddr_in *s_in;
struct sockaddr_in target;
struct netDhcpHeader* packet;
unsigned char *options;
unsigned int ip, val;
int net, ret, count;
unsigned char buf[8];
s_in = (struct sockaddr_in *)&ifr.ifr_addr;
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
s_in->sin_family = AF_INET;
ret = ioctl(sock, SIOCGIFADDR, &ifr);
if(ret == -1) {
#ifdef NET_DEBUG
printf("SIOCGIFADDR error\n");
#endif
return -1;
}
ip = ntohl(s_in->sin_addr.s_addr);
memcpy(macaddr, ifr.ifr_hwaddr.sa_data, 6);
// get buffer area
packet = (struct netDhcpHeader*)malloc(DHCP_HEADER_LEN + 512);
if(packet == 0) return -1;
options = packet->options;
bzero((char*)packet, DHCP_HEADER_LEN + 512);
// build BOOTP/DHCP header
packet->bootp.op = BOOTP_OP_BOOTREQUEST; // request type
packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
packet->bootp.hops = 0;
packet->bootp.xid = htobe32(DhcpTransactID);
packet->bootp.secs = 0;
packet->bootp.ciaddr = htobe32(ip);
packet->bootp.flags = (ip == 0) ? 0 : htobe16(0x8000);
packet->bootp.yiaddr = 0;
packet->bootp.siaddr = 0;
packet->bootp.giaddr = 0;
memcpy(&packet->bootp.chaddr[0], macaddr, 6); // fill client hardware address
// build DHCP request
// begin with magic cookie
packet->cookie = htobe32(0x63825363);
// set operation
count = 0;
if(ip != 0) {
buf[0] = DHCP_MSG_DHCPRELEASE;
} else if(DhcpServerIP == 0) {
buf[0] = DHCP_MSG_DHCPDISCOVER;
} else {
val = htobe32(DhcpServerIP);
count += 2 + 4;
options = dhcpSetOption(options, DHCP_OPT_SERVERID, 4, &val);
if(DhcpClientIP != 0) {
val = htobe32(DhcpClientIP);
count += 2 + 4;
options = dhcpSetOption(options, DHCP_OPT_REQUESTEDIP, 4, &val);
}
buf[0] = DHCP_MSG_DHCPREQUEST;
}
#ifdef NET_DEBUG
switch(buf[0]) {
case DHCP_MSG_DHCPDISCOVER:
printf("DHCP: Discover sending Query\n");
break;
case DHCP_MSG_DHCPREQUEST:
printf("DHCP: Request sending Query\n");
break;
default:
printf("DHCP: Sending Query\n");
}
#endif
count += 2 + 1;
options = dhcpSetOption(options, DHCP_OPT_DHCPMSGTYPE, 1, buf);
buf[0] = BOOTP_HTYPE_ETHERNET;
memcpy(&buf[1], macaddr, 6);
count += 2 + 7;
options = dhcpSetOption(options, DHCP_OPT_CLIENT_IDENT, 7, buf);
if(ip == 0) {
buf[0] = DHCP_OPT_NETMASK;
buf[1] = DHCP_OPT_ROUTERS;
buf[2] = DHCP_OPT_DNSSERVERS;
buf[3] = DHCP_OPT_DOMAINNAME;
count += 2 + 4;
options = dhcpSetOption(options, DHCP_OPT_PARAMREQLIST, 4, buf);
}
count++;
options = dhcpSetOption(options, DHCP_OPT_END, 0, 0);
// send request
target.sin_family = AF_INET;
target.sin_port = htons(DHCP_UDP_SERVER_PORT);
target.sin_addr.s_addr = 0xffffffff;
if(sendto(sock, (char*)packet, DHCP_HEADER_LEN + count, 0, (struct sockaddr *)&target, sizeof(target)) == -1) {
free((char*)packet);
return -1;
}
return 0;
}
static void dhcpTimer(void) {
// this function to be called once per second
// decrement lease time
if(DhcpLeaseTime) DhcpLeaseTime--;
}
static unsigned char dhcpGetOption(unsigned char* options, unsigned char optcode, unsigned char optlen, void* optvalptr) {
unsigned char i;
// parse for desired option
for (;;) {
// skip pad characters
if(*options == DHCP_OPT_PAD) options++;
// break if end reached
else if(*options == DHCP_OPT_END) break;
// check for desired option
else if(*options == optcode) {
// found desired option
// limit size to actual option length
optlen = (optlen < *(options+1)) ? optlen : *(options+1);
//if(*(options+1) < optlen)
// optlen = *(options+1);
// copy contents of option
for(i = 0; i < optlen; i++)
*(((unsigned char*)optvalptr)+i) = *(options+i+2);
// return length of option
return *(options+1);
} else {
// skip to next option
options++;
options+=*options;
options++;
}
}
// failed to find desired option
return 0;
}
static unsigned char* dhcpSetOption(unsigned char* options, unsigned char optcode, unsigned char optlen, void* optvalptr) {
// use current options address as write point
// set optcode
*options++ = optcode;
// set optlen
*options++ = optlen;
// copy in argument/data
while(optlen--) {
*options++ = *(unsigned char*)optvalptr++;
}
// write end marker
*options = DHCP_OPT_END;
// return address of end marker, to be used as a future write point
return options;
}
#ifdef NET_DEBUG
static void dhcpPrintHeader(struct netDhcpHeader* packet) {
int ip;
printf("DHCP Packet:\n");
// print op
printf("Op : ");
switch(packet->bootp.op) {
case BOOTP_OP_BOOTREQUEST: printf("BOOTREQUEST\n"); break;
case BOOTP_OP_BOOTREPLY: printf("BOOTREPLY\n"); break;
default: printf("UNKNOWN\n"); break;
}
// print transaction ID
printf("XID : 0x%08x\n", packet->bootp.xid);
// print client IP address
ip = be32toh(packet->bootp.ciaddr);
printf("%d.%d.%d.%d\n", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
// print 'your' IP address
ip = be32toh(packet->bootp.yiaddr);
printf("%d.%d.%d.%d\n", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
// print server IP address
ip = be32toh(packet->bootp.siaddr);
printf("%d.%d.%d.%d\n", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
// print gateway IP address
ip = be32toh(packet->bootp.giaddr);
printf("%d.%d.%d.%d\n", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
// print client hardware address
printf("%s\n", packet->bootp.chaddr);
}
#endif
extern int start;
int main(int argc, char **argv) {
struct ifreq ifr;
struct sockaddr_in *s_in;
struct sockaddr_in myaddr, target;
struct timeval tv;
struct rtentry stuRTEntry;
struct sockaddr_in stcAddr;
int net, sock, size, ret, retry, msgtype, retry2, addr;
int retrynum, addrlen;
unsigned int ip;
char dev[8], *buf;
char flag;
char buff[INET_ADDRSTRLEN + 1];
FILE *fp;
s_in = (struct sockaddr_in *)&ifr.ifr_addr;
#ifdef NET_DEBUG
printf("DHCP Client 2008/4/15 8:28 coded.\n");
#endif
if(argc == 1 || argc >= 4) return -1;
flag = 0;
retrynum = 3;
if(argc == 3) {
if(argv[2][0] == 'd') {
flag = 1;
} else if(isdigit(argv[2][0])) {
retrynum = atoi(argv[2]);
}
}
strcpy(dev, argv[1]);
buf = malloc(1024);
if(buf == 0) return -1;
for(retry = retrynum;retry >= 0;retry--) {
#if defined(NET_DEBUG) || defined(PGM_DEBUG)
printf("-----Retry %d-----\n", retrynum - retry);
#endif
sock = socket(AF_INET, SOCK_DGRAM, 0);
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
ioctl(sock, SIOCGIFFLAGS, &ifr);
s_in->sin_family = AF_INET;
ioctl(sock, SIOCGIFADDR, &ifr);
ip = ntohl(s_in->sin_addr.s_addr);
ioctl(sock, SIOCGIFHWADDR, &ifr);
memcpy(macaddr, ifr.ifr_hwaddr.sa_data, 6);
close(sock);
if((ifr.ifr_flags & IFF_UP) == 0) {
#ifdef NET_DEBUG
printf("NIC is disabled\n");
#endif
} else {
if(ip != 0) {
// set transaction ID based on mac address
DhcpTransactID = *((unsigned int*)&macaddr) - retry;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock == -1) continue;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(DHCP_UDP_CLIENT_PORT);
myaddr.sin_addr.s_addr = INADDR_ANY;
bind(sock, (struct sockaddr *)&myaddr, sizeof(myaddr));
dhcpRequest(dev, sock);
close(sock);
}
}
// socket
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock == -1) {
#ifdef NET_DEBUG
printf("Fail(3)\n");
#endif
continue;
}
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
s_in->sin_family = AF_INET;
s_in->sin_addr.s_addr = 0;
ioctl(sock, SIOCSIFADDR, &ifr);
s_in->sin_addr.s_addr = 0;
net = ioctl(sock, SIOCSIFNETMASK, &ifr);
ret = ifup(dev, 0, 0);
if(flag == 1) return 0;
if(ret == -1) {
#ifdef NET_DEBUG
printf("Fail(1)\n");
#endif
continue;
}
// get interface mac address
ret = ioctl(sock, SIOCGIFHWADDR, &ifr);
memcpy(macaddr, ifr.ifr_hwaddr.sa_data, 6);
if(ret == -1) {
#ifdef NET_DEBUG
printf("Fail(2)\n");
#endif
continue;
}
// set transaction ID based on mac address
DhcpTransactID = *((unsigned int*)&macaddr) - retry;
// reset lease time
DhcpLeaseTime = 0;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(DHCP_UDP_CLIENT_PORT);
myaddr.sin_addr.s_addr = INADDR_ANY;
tv.tv_sec = 4;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
if(bind(sock, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) {
close(sock);
#ifdef NET_DEBUG
printf("Fail(4)\n");
#endif
continue;
}
DhcpServerIP = 0;
DhcpClientIP = 0;
/***********************/
/**** SEND DISCOVER ****/
/***********************/
if(dhcpRequest(dev, sock) == -1) {
close(sock);
#ifdef NET_DEBUG
printf("Fail(5)\n");
#endif
continue;
}
for(retry2 = 0;retry2 < 3;) {
bzero(buf, 1024);
size = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&target, &addrlen);
if(size <= 0) {
retry2++;
dhcpRequest(dev, sock);
} else {
msgtype = dhcpIn(dev, sock, size, (struct netDhcpHeader *)buf);
if(msgtype != DHCP_MSG_DHCPACK) break;
}
}
if(size <= 0) {
close(sock);
#ifdef NET_DEBUG
printf("Fail(6)\n");
#endif
continue;
}
if(msgtype != DHCP_MSG_DHCPOFFER) {
close(sock);
#ifdef NET_DEBUG
printf("Fail(7)\n");
#endif
continue;
}
/**********************/
/**** SEND REQUEST ****/
/**********************/
if(dhcpRequest(dev, sock) == -1) {
close(sock);
#ifdef NET_DEBUG
printf("Fail(8)\n");
#endif
continue;
}
for(retry2 = 0;retry2 < 3;) {
bzero(buf, 1024);
size = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&target, &addrlen);
if(size <= 0) {
retry2++;
dhcpRequest(dev, sock);
} else {
msgtype = dhcpIn(dev, sock, size, (struct netDhcpHeader *)buf);
if(msgtype != DHCP_MSG_DHCPOFFER) break;
}
}
if(size <= 0) {
#ifdef NET_DEBUG
printf("Fail(9)\n");
printf("DHCP-ACK not received, but set ip.\n");
#endif
} else if(msgtype != DHCP_MSG_DHCPACK) {
#ifdef NET_DEBUG
printf("Fail(10)\n");
printf("DHCP-ACK not received, but set ip.\n");
#endif
}
// assign new network info
strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
s_in->sin_family = AF_INET;
s_in->sin_addr.s_addr = htonl(DhcpClientIP);
ioctl(sock, SIOCSIFADDR, &ifr);
s_in->sin_addr.s_addr = htonl(DhcpNetmask);
ioctl(sock, SIOCSIFNETMASK, &ifr);
ifup(dev, DhcpClientIP, DhcpNetmask);
memset(&stuRTEntry, 0x00, sizeof(stuRTEntry));
stcAddr.sin_family = AF_INET;
stcAddr.sin_port = 0;
stcAddr.sin_addr.s_addr = htonl(DhcpGatewayIP);
memcpy(&stuRTEntry.rt_gateway, (char*)&stcAddr, sizeof(stcAddr));
stuRTEntry.rt_dev = dev;
stuRTEntry.rt_metric = 100;
stuRTEntry.rt_flags = (RTF_UP | RTF_GATEWAY);
stcAddr.sin_addr.s_addr = INADDR_ANY;
memcpy(&stuRTEntry.rt_dst, (char*)&stcAddr, sizeof(stcAddr));
memcpy(&stuRTEntry.rt_genmask, (char*)&stcAddr, sizeof(stcAddr));
ret = ioctl(sock, SIOCADDRT, &stuRTEntry);
close(sock);
addr = htonl(DhcpDNSServerIP);
inet_ntop(AF_INET, &addr, buff, INET_ADDRSTRLEN);
fp = fopen("/etc/resolv.conf", "w");
fprintf(fp, "nameserver %s", buff);
fclose(fp);
free(buf);
return 0;
}
free(buf);
return -1;
}
/// Bootp Header (DHCP is transported by BOOTP/UDP/IP)
struct netBootpHeader {
unsigned char op; ///< Message op-code / message type
unsigned char htype; ///< Hardware address type (Ethernet=1)
unsigned char hlen; ///< Hardware address length (Ethernet=6 byte MAC addr)
unsigned char hops; ///< hop count (client set to zero)
unsigned int xid; ///< Transaction ID (randomly chosen by client, must remain same)
unsigned short secs; ///< Seconds elapsed since DHCP negotiation began (filled by client)
unsigned short flags; ///< Flags
unsigned int ciaddr; ///< Client IP address (filled only if already bound, renewing, or rebinding)
unsigned int yiaddr; ///< 'Your' IP address (client)
unsigned int siaddr; ///< Server IP address
unsigned int giaddr; ///< Gateway IP address
unsigned char chaddr[16]; ///< Client Hardware Address
unsigned char sname[64]; ///< Server Host Name
unsigned char file[128]; ///< Boot file name (null-term string)
} __attribute__ ((packed));
#define BOOTP_HEADER_LEN 236 ///< length of BOOTP header not including options
#define BOOTP_OP_BOOTREQUEST 1 ///< BOOTP Request operation (message from client to server)
#define BOOTP_OP_BOOTREPLY 2 ///< BOOTP Reply operation (message from server to client)
#define BOOTP_HTYPE_ETHERNET 1
#define BOOTP_HLEN_ETHERNET 6
/// DHCP Header
struct netDhcpHeader {
struct netBootpHeader bootp; ///< BOOTP header
unsigned int cookie; ///< magic cookie value
unsigned char options[]; ///< DHCP options
}__attribute__ ((packed));
#define DHCP_HEADER_LEN 240 ///< length of DHCP header not including options
#define DHCP_UDP_SERVER_PORT 67 ///< UDP port where DHCP requests should be sent
#define DHCP_UDP_CLIENT_PORT 68 ///< UDP port clients will receive DHCP replies
#define DHCP_OPT_PAD 0 ///< token padding value (make be skipped)
#define DHCP_OPT_NETMASK 1 ///< subnet mask client should use (4 byte mask)
#define DHCP_OPT_ROUTERS 3 ///< routers client should use (IP addr list)
#define DHCP_OPT_TIMESERVERS 4 ///< time servers client should use (IP addr list)
#define DHCP_OPT_NAMESERVERS 5 ///< name servers client should use (IP addr list)
#define DHCP_OPT_DNSSERVERS 6 ///< DNS servers client should use (IP addr list)
#define DHCP_OPT_HOSTNAME 12 ///< host name client should use (string)
#define DHCP_OPT_DOMAINNAME 15 ///< domain name client should use (string)
#define DHCP_OPT_REQUESTEDIP 50 ///< IP address requested by client (IP address)
#define DHCP_OPT_LEASETIME 51 ///< DHCP Lease Time (uint32 seconds)
#define DHCP_OPT_DHCPMSGTYPE 53 ///< DHCP message type (1 byte)
#define DHCP_OPT_SERVERID 54 ///< Server Identifier (IP address)
#define DHCP_OPT_PARAMREQLIST 55 ///< Paramerter Request List (n OPT codes)
#define DHCP_OPT_RENEWALTIME 58 ///< DHCP Lease Renewal Time (uint32 seconds)
#define DHCP_OPT_REBINDTIME 59 ///< DHCP Lease Rebinding Time (uint32 seconds)
#define DHCP_OPT_CLIENT_IDENT 61 ///< DHCP Client identifer
#define DHCP_OPT_END 255 ///< token end value (marks end of options list)
#define DHCP_MSG_DHCPDISCOVER 1 ///< DISCOVER is broadcast by client to solicit OFFER from any/all DHCP servers.
#define DHCP_MSG_DHCPOFFER 2 ///< OFFER(s) are made to client by server to offer IP address and config info.
#define DHCP_MSG_DHCPREQUEST 3 ///< REQUEST is made my client in response to best/favorite OFFER message.
#define DHCP_MSG_DHCPDECLINE 4 ///< DECLINE may be sent by client to server to indicate IP already in use.
#define DHCP_MSG_DHCPACK 5 ///< ACK is sent to client by server in confirmation of REQUEST, contains config and IP.
#define DHCP_MSG_DHCPNAK 6 ///< NAK is sent to client by server to indicate problem with REQUEST.
#define DHCP_MSG_DHCPRELEASE 7 ///< RELEASE is sent by client to server to relinquish DHCP lease on IP address, etc.
#define DHCP_MSG_DHCPINFORM 8 ///< INFORM is sent by client to server to request config info, IP address configured locally.
static int dhcpIn(char *dev, int sock, int len, struct netDhcpHeader *packet);
static int dhcpRequest(char *dev, int sock);
static void dhcpTimer(void);
static unsigned char dhcpGetOption(unsigned char* options, unsigned char optcode, unsigned char optlen, void* optvalptr);
static unsigned char* dhcpSetOption(unsigned char* options, unsigned char optcode, unsigned char optlen, void* optvalptr);
static void dhcpPrintHeader(struct netDhcpHeader* packet);