📄 dhcp.c
字号:
LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n")); mem_free((void *)dhcp->options_in); dhcp->options_in = NULL; return ERR_MEM; } ptr = (u8_t *)dhcp->msg_in; /* proceed through struct dhcp_msg */ for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_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 %"U16_F" 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 %"U16_F" 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 %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff), (u16_t)(ntohl(addr->addr) >> 8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port)); LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %"U16_F"\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 %"U16_F"\n", (u16_t)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[%"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])); 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=%"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; }}/** * 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=%"U16_F", q->len=%"U16_F, 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 %"U16_F" in options\n", offset)); return &options[offset]; /* skip option */ } else { LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" 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=%"U16_F"\n", offset)); return &options[offset]; /* skip option */ } else { LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\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=%"U16_F"\n", (u16_t)(*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=%"U16_F"\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=%"U32_F"\n", value)); return value;}#endif /* LWIP_DHCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -