bootp.c revision 6de922ee8158732706074aacb20c2a5dc6d4d7a3
/*
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <slirp.h>
/** Entry in the table of known DHCP clients. */
typedef struct
{
bool allocated;
int number;
} BOOTPClient;
/** Number of DHCP clients supported by NAT. */
#define NB_ADDR 16
/* XXX: only DHCP is supported */
{
/*@todo magic validation */
q += 4; /*magic*/
while(*q != RFC1533_END)
{
if (*q == RFC1533_PAD)
continue;
if (*q == tag)
return q;
q++;
len = *q;
q += 1 + len;
}
return NULL;
}
{
int i;
for (i = 0; i < NB_ADDR; i++)
{
if (!bootp_clients[i].allocated)
{
bc = &bootp_clients[i];
return bc;
}
}
return NULL;
}
{
return NULL;
return bc;
}
{
unsigned i;
for (i = 0; i < NB_ADDR; i++)
{
{
return 1;
}
}
return 0;
}
/*
* from RFC 2131 4.3.1
* Field DHCPOFFER DHCPACK DHCPNAK
* ----- --------- ------- -------
* 'op' BOOTREPLY BOOTREPLY BOOTREPLY
* 'htype' (From "Assigned Numbers" RFC)
* 'hlen' (Hardware address length in octets)
* 'hops' 0 0 0
* 'xid' 'xid' from client 'xid' from client 'xid' from client
* DHCPDISCOVER DHCPREQUEST DHCPREQUEST
* message message message
* 'secs' 0 0 0
* 'ciaddr' 0 'ciaddr' from 0
* DHCPREQUEST or 0
* 'yiaddr' IP address offered IP address 0
* to client assigned to client
* 'siaddr' IP address of next IP address of next 0
* bootstrap server bootstrap server
* 'flags' 'flags' from 'flags' from 'flags' from
* client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
* message message message
* 'giaddr' 'giaddr' from 'giaddr' from 'giaddr' from
* client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
* message message message
* 'chaddr' 'chaddr' from 'chaddr' from 'chaddr' from
* client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
* message message message
* 'sname' Server host name Server host name (unused)
* or options or options
* 'file' Client boot file Client boot file (unused)
* name or options name or options
* 'options' options options
*
* Option DHCPOFFER DHCPACK DHCPNAK
* ------ --------- ------- -------
* Requested IP address MUST NOT MUST NOT MUST NOT
* IP address lease time MUST MUST (DHCPREQUEST) MUST NOT
* MUST NOT (DHCPINFORM)
* Use 'file'/'sname' fields MAY MAY MUST NOT
* DHCP message type DHCPOFFER DHCPACK DHCPNAK
* Parameter request list MUST NOT MUST NOT MUST NOT
* Message SHOULD SHOULD SHOULD
* Client identifier MUST NOT MUST NOT MAY
* Vendor class identifier MAY MAY MAY
* Server identifier MUST MUST MUST
* Maximum message size MUST NOT MUST NOT MUST NOT
* All others MAY MAY MUST NOT
*/
{
int i;
for (i = 0; i < NB_ADDR; i++)
{
{
bc = &bootp_clients[i];
return bc;
}
}
return NULL;
}
static struct mbuf *dhcp_create_msg(PNATState pData, struct bootp_t *bp, struct mbuf *m, uint8_t type)
{
uint8_t *q;
#if 0 /*check flags*/
#endif
q += 4;
*q++ = RFC2132_MSG_TYPE;
*q++ = 1;
*q++ = type;
return m;
}
{
int off = 0;
uint8_t *q;
int val;
int added = 0;
q += 7; /* !cookie rfc 2132 + TYPE*/
/*DHCP Offer specific*/
if ( tftp_prefix
&& bootp_filename)
if (is_from_request)
{
}
#ifndef VBOX_WITH_NAT_SERVICE
#else
#endif
do { \
}while(0)
/* appending another value to tag, calculates len of whole block*/
do { \
(q) += (len); \
}while(0)
if (pData->use_dns_proxy)
{
goto skip_dns_servers;
}
{
q_dns_header = q;
}
{
continue; /* first value with head we've ingected before */
}
{
/* Microsoft dhcp client doen't like domain-less dhcp and trimmed packets*/
/* dhcpcd client very sad if no domain name is passed */
}
if (pData->fPassDomain)
{
{
continue;
/* never meet valid separator here in RFC1533*/
if (added != 0)
else
added = 1;
}
}
if (*slirp_hostname)
{
}
}
{
return 7;
}
static int dhcp_send_ack(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m, int is_from_request)
{
int off = 0; /* boot_reply will fill general options and add END before sending response*/
return off;
}
{
int off = 0; /* boot_reply will fill general options and add END before sending response*/
return off;
}
/**
* decoding client messages RFC2131 (4.3.6)
* ---------------------------------------------------------------------
* | |INIT-REBOOT |SELECTING |RENEWING |REBINDING |
* ---------------------------------------------------------------------
* |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT |
* |requested-ip |MUST |MUST |MUST NOT |MUST NOT |
* |ciaddr |zero |zero |IP address |IP address|
* ---------------------------------------------------------------------
*
*/
static int dhcp_decode_request(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, struct mbuf *m)
{
int off;
/*need to understand which type of request we get */
{
/*selecting*/
if (!bc)
{
LogRel(("NAT: DHCP no IP wasn't allocated\n"));
return -1;
}
#if 0
/* DSL xid in request differ from offer */
#endif
}
else
{
{
/* init-reboot */
}
else
{
/*see table 4 rfc2131*/
else
}
}
/*?? renewing ??*/
switch (dhcp_stat)
{
case RENEWING:
{
{
/*if it already here well just do ack, we aren't aware of dhcp time expiration*/
}
else
{
{
return off;
}
{
LogRel(("NAT: can't alloc address. RENEW has been silently ignored\n"));
return -1;
}
}
}
break;
case INIT_REBOOT:
{
return off;
}
{
LogRel(("NAT: can't alloc address. RENEW has been silently ignored\n"));
return -1;
}
break;
case NONE:
return -1;
default:
break;
}
return off;
}
static int dhcp_decode_discover(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag, struct mbuf *m)
{
int off;
/* flag == 1 discover */
if (flag == 1)
{
if (!bc)
{
if (!bc)
{
LogRel(("NAT: DHCP no IP address left\n"));
Log(("no address left\n"));
return -1;
}
}
/*bc isn't NULL */
return off;
}
else
{
/* flag == 0 inform */
{
LogRel(("NAT: DHCP Inform was ignored no boot client was found\n"));
return -1;
}
return off;
}
return -1;
}
static int dhcp_decode_release(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag)
{
return -1;
}
/**
* fields for discovering t
* Field DHCPDISCOVER DHCPREQUEST DHCPDECLINE,
* DHCPINFORM DHCPRELEASE
* ----- ------------ ----------- -----------
* 'op' BOOTREQUEST BOOTREQUEST BOOTREQUEST
* 'htype' (From "Assigned Numbers" RFC)
* 'hlen' (Hardware address length in octets)
* 'hops' 0 0 0
* 'xid' selected by client 'xid' from server selected by
* DHCPOFFER message client
* 'secs' 0 or seconds since 0 or seconds since 0
* DHCP process started DHCP process started
* 'flags' Set 'BROADCAST' Set 'BROADCAST' 0
* flag if client flag if client
* requires broadcast requires broadcast
* reply reply
* 'ciaddr' 0 (DHCPDISCOVER) 0 or client's 0 (DHCPDECLINE)
* client's network address client's network
* (DHCPINFORM) (DHCPRELEASE)
* 'yiaddr' 0 0 0
* 'siaddr' 0 0 0
* 'giaddr' 0 0 0
* 'chaddr' client's hardware client's hardware client's hardware
* address address address
* 'sname' options, if options, if (unused)
* indicated in indicated in
* option; otherwise option; otherwise
* unused unused
* 'file' options, if options, if (unused)
* indicated in indicated in
* option; otherwise option; otherwise
* unused unused
* 'options' options options (unused)
* Requested IP address MAY MUST (in MUST
* (DISCOVER) SELECTING or (DHCPDECLINE),
* MUST NOT INIT-REBOOT) MUST NOT
* (INFORM) MUST NOT (in (DHCPRELEASE)
* BOUND or
* RENEWING)
* IP address lease time MAY MAY MUST NOT
* (DISCOVER)
* MUST NOT
* (INFORM)
* Use 'file'/'sname' fields MAY MAY MAY
* DHCP message type DHCPDISCOVER/ DHCPREQUEST DHCPDECLINE/
* DHCPINFORM DHCPRELEASE
* Client identifier MAY MAY MAY
* Vendor class identifier MAY MAY MUST NOT
* Server identifier MUST NOT MUST (after MUST
* SELECTING)
* MUST NOT (after
* INIT-REBOOT,
* BOUND, RENEWING
* or REBINDING)
* Parameter request list MAY MAY MUST NOT
* Maximum message size MAY MAY MUST NOT
* Message SHOULD NOT SHOULD NOT SHOULD
* Site-specific MAY MAY MUST NOT
* All others MAY MAY MUST NOT
*
*/
{
int rc;
int pmsg_type;
int flag = 0;
pmsg_type = 0;
p = buf;
if (size < 5)
return;
return;
Assert(p);
if (p == NULL)
return;
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
#else
#endif
{
LogRel(("NAT: can't alocate memory for response!\n"));
return;
}
switch(*(p+2))
{
case DHCPDISCOVER:
flag = 1;
/**/
case DHCPINFORM:
if (rc > 0)
goto reply;
break;
case DHCPREQUEST:
if (rc > 0)
goto reply;
break;
case DHCPRELEASE:
flag = 1;
#if 0
case DHCPDECLINE:
#endif
if (rc > 0)
goto reply;
break;
default:
AssertMsgFailed(("unsupported DHCP message type"));
}
Assert(m);
/*silently ignore*/
return;
return;
}
{
int nack;
Assert((m));
q += off;
#ifndef VBOX_WITH_NAT_SERVICE
#else
#endif
*q++ = RFC1533_END; /*end of message */
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
#endif
- sizeof(struct ip)
- sizeof(struct udphdr);
+ sizeof(struct ip);
else
}
{
{
}
}
{
int rc = 1;
int i;
return rc;
for (i = 0; i < NB_ADDR; i++)
{
if ( bootp_clients[i].allocated
{
rc = 0;
break;
}
}
return rc;
}
{
int rc = 1;
int i;
return rc;
for (i = 0; i < NB_ADDR; i++)
{
if ( bootp_clients[i].allocated
{
rc = 0;
break;
}
}
return rc;
}
/*
* Initialize dhcp server
* @returns 0 - if initialization is ok, non-zero otherwise
*/
{
int rc = 1;
rc = 0;
return rc;
}
{
return 0;
}