📄 dhcp.c
字号:
/* 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 voiddhcp_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_tdhcp_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 voiddhcp_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 voiddhcp_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->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; }}#endif /* LWIP_DHCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -