📄 dhcp.c
字号:
case(DHCP_OPTION_ROUTER):
decode_len = 4; /* only copy the first given router */
LWIP_ASSERT("len >= decode_len", len >= decode_len);
decode_idx = DHCP_OPTION_IDX_ROUTER;
break;
case(DHCP_OPTION_DNS_SERVER):
/* special case: there might be more than one server */
LWIP_ASSERT("len % 4 == 0", len % 4 == 0);
/* limit number of DNS servers */
decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
LWIP_ASSERT("len >= decode_len", len >= decode_len);
decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
break;
case(DHCP_OPTION_LEASE_TIME):
LWIP_ASSERT("len == 4", len == 4);
decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
break;
case(DHCP_OPTION_OVERLOAD):
LWIP_ASSERT("len == 1", len == 1);
decode_idx = DHCP_OPTION_IDX_OVERLOAD;
break;
case(DHCP_OPTION_MESSAGE_TYPE):
LWIP_ASSERT("len == 1", len == 1);
decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
break;
case(DHCP_OPTION_SERVER_ID):
LWIP_ASSERT("len == 4", len == 4);
decode_idx = DHCP_OPTION_IDX_SERVER_ID;
break;
case(DHCP_OPTION_T1):
LWIP_ASSERT("len == 4", len == 4);
decode_idx = DHCP_OPTION_IDX_T1;
break;
case(DHCP_OPTION_T2):
LWIP_ASSERT("len == 4", len == 4);
decode_idx = DHCP_OPTION_IDX_T2;
break;
default:
decode_len = 0;
LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op));
break;
}
offset += len + 2;
if (decode_len > 0) {
u32_t value = 0;
u16_t copy_len;
decode_next:
LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx));
copy_len = LWIP_MIN(decode_len, 4);
pbuf_copy_partial(q, &value, copy_len, val_offset);
if (decode_len > 4) {
/* decode more than one u32_t */
LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0);
dhcp_got_option(dhcp, decode_idx);
dhcp_set_option_value(dhcp, decode_idx, htonl(value));
decode_len -= 4;
val_offset += 4;
decode_idx++;
goto decode_next;
} else if (decode_len == 4) {
value = ntohl(value);
} else {
LWIP_ASSERT("invalid decode_len", decode_len == 1);
value = ((u8_t*)&value)[0];
}
dhcp_got_option(dhcp, decode_idx);
dhcp_set_option_value(dhcp, decode_idx, value);
}
if (offset >= q->len) {
offset -= q->len;
offset_max -= q->len;
q = q->next;
options = (u8_t*)q->payload;
}
}
/* is this an overloaded message? */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {
u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD);
dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD);
if (overload == DHCP_OVERLOAD_FILE) {
parse_file_as_options = 1;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
} else if (overload == DHCP_OVERLOAD_SNAME) {
parse_sname_as_options = 1;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
} else if (overload == DHCP_OVERLOAD_SNAME_FILE) {
parse_sname_as_options = 1;
parse_file_as_options = 1;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
} else {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
}
#if LWIP_DHCP_BOOTP_FILE
if (!parse_file_as_options) {
/* only do this for ACK messages */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))
/* copy bootp file name, don't care for sname (server hostname) */
pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS);
/* make sure the string is really NULL-terminated */
dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;
}
#endif /* LWIP_DHCP_BOOTP_FILE */
}
if (parse_file_as_options) {
/* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */
parse_file_as_options = 0;
options_idx = DHCP_FILE_OFS;
options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;
goto again;
} else if (parse_sname_as_options) {
parse_sname_as_options = 0;
options_idx = DHCP_SNAME_OFS;
options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;
goto again;
}
return ERR_OK;
}
/**
* If an incoming DHCP message is in response to us, then trigger the state machine
*/
static void
dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
struct netif *netif = (struct netif *)arg;
struct dhcp *dhcp = netif->dhcp;
struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
u8_t msg_type;
u8_t i;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port));
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
/* prevent warnings about unused arguments */
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(addr);
LWIP_UNUSED_ARG(port);
LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
if (p->len < DHCP_MIN_REPLY_LEN) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n"));
goto free_pbuf_and_return;
}
if (reply_msg->op != DHCP_BOOTREPLY) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
goto free_pbuf_and_return;
}
/* iterate through hardware address and match against DHCP message */
for (i = 0; i < netif->hwaddr_len; i++) {
if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
(u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
goto free_pbuf_and_return;
}
}
/* match transaction ID against what we expected */
if (ntohl(reply_msg->xid) != dhcp->xid) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
goto free_pbuf_and_return;
}
/* option fields could be unfold? */
if (dhcp_parse_reply(dhcp, p) != ERR_OK) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("problem unfolding DHCP message - too short on memory?\n"));
goto free_pbuf_and_return;
}
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
/* obtain pointer to DHCP message type */
if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
goto free_pbuf_and_return;
}
/* read DHCP message type */
msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE);
/* message type is DHCP ACK? */
if (msg_type == DHCP_ACK) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n"));
/* in requesting state? */
if (dhcp->state == DHCP_REQUESTING) {
dhcp_handle_ack(netif);
#if DHCP_DOES_ARP_CHECK
/* check if the acknowledged lease address is already in use */
dhcp_check(netif);
#else
/* bind interface to the acknowledged lease address */
dhcp_bind(netif);
#endif
}
/* already bound to the given lease address? */
else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
dhcp_bind(netif);
}
}
/* received a DHCP_NAK in appropriate state? */
else if ((msg_type == DHCP_NAK) &&
((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
(dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n"));
dhcp_handle_nak(netif);
}
/* received a DHCP_OFFER in DHCP_SELECTING state? */
else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
dhcp->request_timeout = 0;
/* remember offered lease */
dhcp_handle_offer(netif);
}
free_pbuf_and_return:
dhcp->msg_in = NULL;
pbuf_free(p);
}
/**
* Create a DHCP request, fill in common headers
*
* @param netif the netif under DHCP control
* @param dhcp dhcp control struct
* @param message_type message type of the request
*/
static err_t
dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
{
u16_t i;
#ifndef DHCP_GLOBAL_XID
/** default global transaction identifier starting value (easy to match
* with a packet analyser). We simply increment for each new request.
* Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
* at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
static u32_t xid = 0xABCD0000;
#else
static u32_t xid;
static u8_t xid_initialised = 0;
if (!xid_initialised) {
xid = DHCP_GLOBAL_XID;
xid_initialised = !xid_initialised;
}
#endif
LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;);
LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL);
LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
if (dhcp->p_out == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("dhcp_create_msg(): could not allocate pbuf\n"));
return ERR_MEM;
}
LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg",
(dhcp->p_out->len >= sizeof(struct dhcp_msg)));
/* reuse transaction identifier in retransmissions */
if (dhcp->tries == 0) {
xid++;
}
dhcp->xid = xid;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
("transaction id xid(%"X32_F")\n", xid));
dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
dhcp->msg_out->op = DHCP_BOOTREQUEST;
/* TODO: make link layer independent */
dhcp->msg_out->htype = DHCP_HTYPE_ETH;
dhcp->msg_out->hlen = netif->hwaddr_len;
dhcp->msg_out->hops = 0;
dhcp->msg_out->xid = htonl(dhcp->xid);
dhcp->msg_out->secs = 0;
/* we don't need the broadcast flag since we can receive unicast traffic
before being fully configured! */
dhcp->msg_out->flags = 0;
ip_addr_set_zero(&dhcp->msg_out->ciaddr);
/* set ciaddr to netif->ip_addr based on message_type and state */
if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) ||
((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */
((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) {
ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr);
}
ip_addr_set_zero(&dhcp->msg_out->yiaddr);
ip_addr_set_zero(&dhcp->msg_out->siaddr);
ip_addr_set_zero(&dhcp->msg_out->giaddr);
for (i = 0; i < DHCP_CHADDR_LEN; i++) {
/* copy netif hardware address, pad with zeroes */
dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
}
for (i = 0; i < DHCP_SNAME_LEN; i++) {
dhcp->msg_out->sname[i] = 0;
}
for (i = 0; i < DHCP_FILE_LEN; i++) {
dhcp->msg_out->file[i] = 0;
}
dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
dhcp->options_out_len = 0;
/* fill options field with an incrementing array (for debugging purposes) */
for (i = 0; i < DHCP_OPTIONS_LEN; i++) {
dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */
}
/* Add option MESSAGE_TYPE */
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
dhcp_option_byte(dhcp, message_type);
return ERR_OK;
}
/**
* Free previously allocated memory used to send a DHCP request.
*
* @param dhcp the dhcp struct to free the request from
*/
static void
dhcp_delete_msg(struct dhcp *dhcp)
{
LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;);
LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
if (dhcp->p_out != NULL) {
pbuf_free(dhcp->p_out);
}
dhcp->p_out = NULL;
dhcp->msg_out = NULL;
}
/**
* Add a DHCP message trailer
*
* Adds the END option to the DHCP message, and if
* necessary, up to three padding bytes.
*
* @param dhcp DHCP state structure
*/
static void
dhcp_option_trailer(struct dhcp *dhcp)
{
LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);
LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
/* packet is too small, or not 4 byte aligned? */
while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
/* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp-
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -