📄 pcdhcp.c
字号:
char *p = tftp_set_boot_fname ((const char*)(opt+2), opt[1]);
TRACE ("BOOT-file: `%s'\r\n", p);
}
break;
#endif
case END_OPT:
TRACE ("got end-option\r\n", 0);
return (got_offer);
default:
TRACE ("Ignoring option %d\r\n", *opt);
break;
}
opt += *(opt+1) + 2;
}
if (extra_options.data)
{
struct dhcp ext;
len = min (extra_options.size, sizeof(ext.dh_opt));
extra_options.data [len] = END_OPT;
memcpy (ext.dh_opt, extra_options.data, len);
DHCP_offer (&ext);
}
return (got_offer);
}
/*-------------------------------------------------------------------*/
static int DHCP_ack (struct dhcp *in)
{
BYTE *opt = (BYTE*) &in->dh_opt[4];
return (opt[0] == DHCP_MSG_TYPE && opt[1] == 1 && opt[2] == DHCP_ACK);
}
/*-------------------------------------------------------------------*/
static int DHCP_nack (struct dhcp *in)
{
BYTE *opt = (BYTE*) &in->dh_opt[4];
return (opt[0] == DHCP_MSG_TYPE && opt[1] == 1 && opt[2] == DHCP_NAK);
}
/*-------------------------------------------------------------------*/
void DHCP_release (void)
{
struct udp_Socket socket;
struct dhcp dhcp_out;
if (!configured)
return;
#if 0 /* !!to-do: if DHCP-config is saved on disk, use that next time */
if (DHCP_remaining_lease() > 10)
return;
set_config ("dhcp_iplease", 0);
#endif
TRACE ("Sending DHCP release\r\n", 0); /* release is unicast */
udp_open (&socket, IPPORT_BOOTPC, dhcp_server, IPPORT_BOOTPS, NULL);
sock = (sock_type*) &socket;
DHCP_release_decline (&dhcp_out, DHCP_RELEASE, NULL);
sock_close (sock);
}
/*-------------------------------------------------------------------*/
static sock_type *dhcp_open (int reconf)
{
static udp_Socket socket;
DWORD host;
outs (reconf ? _LANG("Reconfiguring through DHCP..")
: _LANG("Configuring through DHCP..."));
if (bcast_on)
host = (DWORD)-1;
else host = dhcp_server;
udp_open (&socket, IPPORT_BOOTPC, host, IPPORT_BOOTPS, NULL);
return (sock_type*)&socket;
}
/*-------------------------------------------------------------------*/
static void arp_add_server (sock_type *sock)
{
if ((_pktdevclass == PD_ETHER || _pktdevclass == PD_TOKEN) &&
memcmp(&sock->udp.hisethaddr, &_eth_brdcast, sizeof(_eth_brdcast)))
_arp_add_cache (dhcp_server, &sock->udp.hisethaddr, TRUE);
}
/*
* _dodhcp() - our first time (booting) DHCP handler.
* Doesn't hurt that it's blocking, but should be rewitten together
* with dhcp_renew() to make a proper state machine.
*/
int _dodhcp (void)
{
struct dhcp dhcp_out;
struct dhcp dhcp_in;
int status, loop, len;
int save_mtu = mtu;
mtu = ETH_MAX_DATA;
sock = dhcp_open (0);
start_time = time (NULL);
for (loop = 0; loop < max_retries; loop++)
{
DWORD sendtimeout;
TRACE ("Sending DHCP discover (%d)\r\n", loop);
if (!DHCP_discover (&dhcp_out))
goto sock_exit;
sendtimeout = set_timeout (dhcp_timeout * 1000);
while (!chk_timeout(sendtimeout))
{
sock_tick (sock, &status);
if (!sock_dataready(sock))
continue;
len = sock_fastread (sock, (BYTE*)&dhcp_in, sizeof(dhcp_in));
if (len < DHCP_MIN_SIZE || /* too short packet */
dhcp_in.dh_op != BOOTREPLY || /* not a BOOT reply */
dhcp_in.dh_xid != dhcp_out.dh_xid) /* not our exchange ID */
continue;
gateway = dhcp_in.dh_giaddr;
if (!got_offer && DHCP_offer(&dhcp_in))
{
TRACE ("Got DHCP offer\r\n", 0);
RandomWait (1000, 2000);
if (dhcp_iplease == 0L) /* cannot happen ? */
dhcp_iplease = 3600L;
if (dhcp_renewal == 0L)
dhcp_renewal = dhcp_iplease / 2; /* default T1 time */
if (dhcp_rebind == 0)
dhcp_rebind = dhcp_iplease * 7 / 8; /* default T2 time */
TRACE ("Sending DHCP request\r\n", 0);
DHCP_request (&dhcp_out, renewing, dhcp_in.dh_yiaddr);
/* Remember my_ip_addr from OFFER because WinNT server
* doesn't include it in ACK message.
*/
my_ip_addr = ((udp_Socket*)sock)->myaddr = intel (dhcp_in.dh_yiaddr);
TRACE ("my_ip_addr = %s\r\n", INET_NTOA(my_ip_addr));
sendtimeout = set_timeout (10000);
continue;
}
if (DHCP_ack(&dhcp_in))
{
if (!DHCP_process_ack(&dhcp_out))
continue;
dhcp_set_timers();
addwattcpd (dhcp_daemon);
#if 0
/* !!to-do: save DHCP-config to disk (temp-file) for use next
* time we boot. Hence no need to do all this each time
*/
#endif
goto sock_exit; /* OK return */
}
if (DHCP_nack(&dhcp_in))
{
TRACE ("Got DHCP nack\r\n", 0);
my_ip_addr = 0;
break; /* retry */
}
memset (&dhcp_in, 0, sizeof(dhcp_in));
continue;
}
}
sock_exit:
sock_err:
if (dhcp_server)
arp_add_server (sock);
sock_close (sock);
dhcp_options_free();
mtu = save_mtu;
return (my_ip_addr != 0);
}
/*
* dhcp_renew() - enter renewing or rebinding state
* !! to-do: make this a non-blocking state-machine.
*/
static int dhcp_renew (void)
{
struct dhcp dhcp_out;
struct dhcp dhcp_in;
int status, loop, len;
sock = dhcp_open (1);
start_time = time (NULL);
for (loop = 0; loop < max_retries; loop++)
{
DWORD sendtimeout;
TRACE ("Sending DHCP request\r\n", 0);
if (!DHCP_request (&dhcp_out, renewing, intel(my_ip_addr)))
goto sock_exit;
sendtimeout = set_timeout (dhcp_timeout * 1000);
while (!chk_timeout(sendtimeout))
{
sock_tick (sock, &status);
if (!sock_dataready(sock))
continue;
len = sock_fastread (sock, (BYTE*)&dhcp_in, sizeof(dhcp_in));
if (len < DHCP_MIN_SIZE || /* too short packet */
dhcp_in.dh_op != BOOTREPLY || /* not a BOOT reply */
dhcp_in.dh_xid != dhcp_out.dh_xid) /* not our exchange ID */
continue;
gateway = dhcp_in.dh_giaddr;
if (DHCP_ack(&dhcp_in))
{
if (!DHCP_process_ack(&dhcp_out))
continue;
dhcp_set_timers();
addwattcpd (dhcp_daemon);
goto sock_exit; /* OK return */
}
if (DHCP_nack(&dhcp_in))
{
TRACE ("Got DHCP nack\r\n", 0);
my_ip_addr = 0;
break; /* retry */
}
memset (&dhcp_in, 0, sizeof(dhcp_in));
continue;
}
}
sock_exit:
sock_err:
sock_close (sock);
return (my_ip_addr != 0);
}
/*-------------------------------------------------------------------*/
static void dhcp_option_add (BYTE *opt, int max)
{
int len = 0;
char *add;
extra_options.data = realloc (extra_options.data, max);
if (!extra_options.data)
return;
add = (char*)&extra_options.data + extra_options.size;
/* Loop over `opt' and append to `add'. Strip away END_OPT
* and PAD_OPT options.
*/
while (opt < opt + max)
{
if (*opt == PAD_OPT)
continue;
if (*opt == END_OPT)
return;
len = opt[1];
memcpy (add, opt, len+2);
add += len + 2;
opt += len + 2;
extra_options.size += len + 2;
}
}
/*-------------------------------------------------------------------*/
static void dhcp_options_free (void)
{
if (extra_options.data)
{
free (extra_options.data);
extra_options.data = NULL;
extra_options.size = 0;
}
}
/*-------------------------------------------------------------------*/
void _dodhcp_inform (void)
{
struct dhcp dhcp_out;
struct dhcp dhcp_in;
udp_Socket socket;
int status, len;
DWORD sendtimeout;
if (!do_inform || !dhcp_server)
return;
udp_open (&socket, IPPORT_BOOTPC, dhcp_server, IPPORT_BOOTPS, NULL);
sock = (sock_type*) &socket;
start_time = time (NULL);
if (trace_on || debug_on)
outs (_LANG("Sending DHCP inform.."));
DHCP_inform (&dhcp_out);
sendtimeout = set_timeout (dhcp_timeout * 1000);
while (!chk_timeout(sendtimeout))
{
sock_tick (sock, &status);
if (!sock_dataready(sock))
continue;
len = sock_fastread (sock, (BYTE*)&dhcp_in, sizeof(dhcp_in));
if (len < DHCP_MIN_SIZE || /* too short packet */
dhcp_in.dh_op != BOOTREPLY || /* not a BOOT reply */
dhcp_in.dh_xid != dhcp_out.dh_xid) /* not our exchange ID */
continue;
if (DHCP_ack(&dhcp_in))
break;
}
sock_err:
sock_close (sock);
if (chk_timeout(sendtimeout))
TRACE ("Got no DHCP ack\r\n", 0);
else TRACE ("Got DHCP ack\r\n", 0);
}
/*-------------------------------------------------------------------*/
static void dhcp_set_timers (void)
{
check_timer = set_timeout (1000); /* count down each sec */
renewal_count = (long)dhcp_renewal;
rebind_count = (long)dhcp_rebind;
if (rebind_count == renewal_count)
rebind_count += 10; /* add 10 seconds */
}
/*
* dhcp_daemon() - called from tcp_tick()
*/
static void dhcp_daemon (void)
{
BOOL t1, t2;
if (!chk_timeout(check_timer))
return;
check_timer = set_timeout (1000);
t1 = (--renewal_count <= 0);
t2 = (--rebind_count <= 0);
if (!t1 && !t2)
return;
renewing = 1;
bcast_on = 0; /* can Unicast now */
if (t1) gateway = 0; /* don't use relay agent */
if (t2) bcast_on = 1; /* must use Broadcast */
TRACE ("DHCP daemon timeout: %s\r\n", t1 ? "RENEWAL" : "REBIND");
suggestLease = dhcp_iplease;
delwattcpd (dhcp_daemon); /* don't run daemon now */
dhcp_renew();
}
/*
* Parse a list of DHCP-request options from config-file.
* e.g DHCP_REQ_LIST = 1,23,24,28,36
*/
static int set_request_list (char *options)
{
static int init = 0;
int num = 0;
int maxreq = 312 - 27; /* sizeof(dh_opt) - min size of rest */
BYTE *list, *start, *tok, *end;
if (init || (list = calloc(maxreq,1)) == NULL)
return (0);
init = 1;
start = list;
end = start + maxreq - 1;
tok = (BYTE*) strtok (options, ", \t");
while (tok && list < end)
{
*list = atoi ((const char*)tok);
tok = (BYTE*) strtok (NULL, ", \t");
/* If request list start with Pad option ("DHCP.REQ_LIST=0"),
* disable options all-together.
*/
if (num == 0 && *list == '0')
break;
num++;
list++;
}
request_list.data = start;
request_list.size = num;
#if 0 /* test */
{
int i;
for (i = 0; i < request_list.size; i++)
printf ("%2d, ", request_list.data[i]);
puts ("");
}
#endif
return (1);
}
static BYTE *put_request_list (BYTE *opt, int filled)
{
struct dhcp dhcp;
int size = min (request_list.size, sizeof(dhcp.dh_opt)-filled-1);
/* room for END_OPT ^ */
if (size > 0 && request_list.data)
{
*opt++ = DHCP_PARAM_REQUEST;
*opt++ = request_list.size;
memcpy (opt, request_list.data, size);
opt += size;
}
return (opt);
}
/*-------------------------------------------------------------------*/
static void (*prev_hook) (const char*, const char*) = NULL;
static void DHCP_config (const char *name, const char *value)
{
static struct config_table dhcp_cfg[] = {
{ "REQ_LIST", ARG_FUNC, (void*)set_request_list },
{ "TRACE", ARG_ATOI, (void*)&trace_on },
{ "BCAST", ARG_ATOI, (void*)&bcast_flag },
{ "INFORM", ARG_ATOI, (void*)&do_inform },
{ "TIMEOUT", ARG_ATOI, (void*)&dhcp_timeout },
{ "RETRIES", ARG_ATOI, (void*)&max_retries },
{ "ARPCHECK", ARG_ATOI, (void*)&arp_check_ip },
{ "HOST", ARG_RESOLVE,(void*)&dhcp_server },
{ NULL }
};
if (!parse_config_table(&dhcp_cfg[0], "DHCP.", name, value) && prev_hook)
(*prev_hook) (name, value);
}
void DHCP_init (void)
{
prev_hook = usr_init;
usr_init = DHCP_config;
}
#endif /* USE_DHCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -