📄 dhcp.c
字号:
*ptr++ = ((u8_t *)p->payload)[j++];
/* reached end of pbuf? */
if (j == p->len)
{
/* proceed to next pbuf in chain */
p = p->next;
j = 0;
}
}
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %u bytes into dhcp->msg_in[]\n", i));
if (dhcp->options_in != NULL) {
ptr = (u8_t *)dhcp->options_in;
/* proceed through options */
for (i = 0; i < dhcp->options_in_len; i++) {
*ptr++ = ((u8_t *)p->payload)[j++];
/* reached end of pbuf? */
if (j == p->len) {
/* proceed to next pbuf in chain */
p = p->next;
j = 0;
}
}
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %u bytes to dhcp->options_in[]\n", i));
}
return ERR_OK;
}
/**
* Free the incoming DHCP message including contiguous copy of
* its DHCP options.
*
*/
static void dhcp_free_reply(struct dhcp *dhcp)
{
if (dhcp->msg_in != NULL) {
mem_free((void *)dhcp->msg_in);
dhcp->msg_in = NULL;
}
if (dhcp->options_in) {
mem_free((void *)dhcp->options_in);
dhcp->options_in = NULL;
dhcp->options_in_len = 0;
}
LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));
}
/**
* 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, struct ip_addr *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 *options_ptr;
u8_t msg_type;
u8_t i;
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %u.%u.%u.%u port %u\n", p,
(unsigned int)(ntohl(addr->addr) >> 24 & 0xff), (unsigned int)(ntohl(addr->addr) >> 16 & 0xff),
(unsigned int)(ntohl(addr->addr) >> 8 & 0xff), (unsigned int)(ntohl(addr->addr) & 0xff), port));
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %u\n", p->len));
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %u\n", p->tot_len));
/* prevent warnings about unused arguments */
(void)pcb; (void)addr; (void)port;
dhcp->p = p;
/* TODO: check packet length before reading them */
if (reply_msg->op != DHCP_BOOTREPLY) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %u\n", reply_msg->op));
pbuf_free(p);
dhcp->p = NULL;
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 | DBG_TRACE | 2, ("netif->hwaddr[%u]==%02x != reply_msg->chaddr[%u]==%02x\n",
i, netif->hwaddr[i], i, reply_msg->chaddr[i]));
pbuf_free(p);
dhcp->p = NULL;
return;
}
}
/* match transaction ID against what we expected */
if (ntohl(reply_msg->xid) != dhcp->xid) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id mismatch\n"));
pbuf_free(p);
dhcp->p = NULL;
return;
}
/* option fields could be unfold? */
if (dhcp_unfold_reply(dhcp) != ERR_OK) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
pbuf_free(p);
dhcp->p = NULL;
return;
}
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
/* obtain pointer to DHCP message type */
options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);
if (options_ptr == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
pbuf_free(p);
dhcp->p = NULL;
return;
}
/* read DHCP message type */
msg_type = dhcp_get_option_byte(options_ptr + 2);
/* message type is DHCP ACK? */
if (msg_type == DHCP_ACK) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n"));
/* in requesting state? */
if (dhcp->state == DHCP_REQUESTING) {
dhcp_handle_ack(netif);
dhcp->request_timeout = 0;
#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->request_timeout = 0;
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 | DBG_TRACE | 1, ("DHCP_NAK received\n"));
dhcp->request_timeout = 0;
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 | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
dhcp->request_timeout = 0;
/* remember offered lease */
dhcp_handle_offer(netif);
}
pbuf_free(p);
dhcp->p = NULL;
}
static err_t dhcp_create_request(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
u16_t i;
LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);
LWIP_ASSERT("dhcp_create_request: 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 | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
return ERR_MEM;
}
/* give unique transaction identifier to this request */
dhcp->xid = 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;
/* TODO: make link layer independent */
dhcp->msg_out->hlen = DHCP_HLEN_ETH;
dhcp->msg_out->hops = 0;
dhcp->msg_out->xid = htonl(dhcp->xid);
dhcp->msg_out->secs = 0;
dhcp->msg_out->flags = 0;
dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
dhcp->msg_out->yiaddr.addr = 0;
dhcp->msg_out->siaddr.addr = 0;
dhcp->msg_out->giaddr.addr = 0;
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 = htonl(0x63825363UL);
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] = i;
return ERR_OK;
}
static void dhcp_delete_request(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_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.
*/
static void dhcp_option_trailer(struct dhcp *dhcp)
{
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=%u, DHCP_OPTIONS_LEN=%u", dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
/* add a fill/padding byte */
dhcp->msg_out->options[dhcp->options_out_len++] = 0;
}
}
/**
* Find the offset of a DHCP option inside the DHCP message.
*
* @param client DHCP client
* @param option_type
*
* @return a byte offset into the UDP message where the option was found, or
* zero if the given option was not found.
*/
static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
{
u8_t overload = DHCP_OVERLOAD_NONE;
/* options available? */
if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {
/* start with options field */
u8_t *options = (u8_t *)dhcp->options_in;
u16_t offset = 0;
/* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {
/* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%u, q->len=%u", msg_offset, q->len)); */
/* are the sname and/or file field overloaded with options? */
if (options[offset] == DHCP_OPTION_OVERLOAD) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n"));
/* skip option type and length */
offset += 2;
overload = options[offset++];
}
/* requested option found */
else if (options[offset] == option_type) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %u in options\n", offset));
return &options[offset];
/* skip option */
} else {
LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %u in options\n", options[offset]));
/* skip option type */
offset++;
/* skip option length, and then length bytes */
offset += 1 + options[offset];
}
}
/* is this an overloaded message? */
if (overload != DHCP_OVERLOAD_NONE) {
u16_t field_len;
if (overload == DHCP_OVERLOAD_FILE) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n"));
options = (u8_t *)&dhcp->msg_in->file;
field_len = DHCP_FILE_LEN;
} else if (overload == DHCP_OVERLOAD_SNAME) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n"));
options = (u8_t *)&dhcp->msg_in->sname;
field_len = DHCP_SNAME_LEN;
/* TODO: check if else if () is necessary */
} else {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n"));
options = (u8_t *)&dhcp->msg_in->sname;
field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
}
offset = 0;
/* at least 1 byte to read and no end marker */
while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {
if (options[offset] == option_type) {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%u\n", offset));
return &options[offset];
/* skip option */
} else {
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %u\n", options[offset]));
/* skip option type */
offset++;
offset += 1 + options[offset];
}
}
}
}
return 0;
}
/**
* Return the byte of DHCP option data.
*
* @param client DHCP client.
* @param ptr pointer obtained by dhcp_get_option_ptr().
*
* @return byte value at the given address.
*/
static u8_t dhcp_get_option_byte(u8_t *ptr)
{
LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%u\n", *ptr));
return *ptr;
}
/**
* Return the 16-bit value of DHCP option data.
*
* @param client DHCP client.
* @param ptr pointer obtained by dhcp_get_option_ptr().
*
* @return byte value at the given address.
*/
static u16_t dhcp_get_option_short(u8_t *ptr)
{
u16_t value;
value = *ptr++ << 8;
value |= *ptr;
LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%u\n", value));
return value;
}
/**
* Return the 32-bit value of DHCP option data.
*
* @param client DHCP client.
* @param ptr pointer obtained by dhcp_get_option_ptr().
*
* @return byte value at the given address.
*/
static u32_t dhcp_get_option_long(u8_t *ptr)
{
u32_t value;
value = (u32_t)(*ptr++) << 24;
value |= (u32_t)(*ptr++) << 16;
value |= (u32_t)(*ptr++) << 8;
value |= (u32_t)(*ptr++);
LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%lu\n", value));
return value;
}
#endif /* LWIP_DHCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -