/**************************************************************************** * Name: dhcpc_request ****************************************************************************/ static int dhcpc_request(void *handle, struct dhcpc_state *presult) { if (!handle) { ndbg("ERROR : handle must not be null\n"); return -100; } if (!presult) { ndbg("ERROR : presult must not be null\n"); return -100; } struct dhcpc_state_s *pdhcpc = (struct dhcpc_state_s *)handle; g_pResult = presult; struct in_addr oldaddr; struct in_addr newaddr; uint8_t msgtype; int retries = 0, result = 0; char *intf; #define CNT_MAX_DISCOVER 5 #define CNT_MAX_REQUEST 5 /* Save the currently assigned IP address (should be INADDR_ANY) */ oldaddr.s_addr = 0; intf = pdhcpc->nic; int ret = netlib_get_ipv4addr(intf, &oldaddr); if (ret == -1) { printf("Set IPv4 fail\n"); } /* Loop until we receive the lease (or an error occurs) */ /* Set the IP address to INADDR_ANY. */ newaddr.s_addr = INADDR_ANY; if (netlib_set_ipv4addr(intf, &newaddr) == ERROR) { ndbg("netlib_set_ipv4addr failed\n"); } /* Loop sending DISCOVER until we receive an OFFER from a DHCP * server. We will lock on to the first OFFER and decline any * subsequent offers (which will happen if there are more than one * DHCP servers on the network. */ g_dhcpc_state = STATE_INITIAL; do { /* Get the DHCPOFFER response */ if (++retries > CNT_MAX_DISCOVER) { /* reach max try */ return -2; } ndbg("Send Discover Packet\n"); result = dhcpc_sendmsg(pdhcpc, g_pResult, DHCPDISCOVER); usleep(100000); if (result < 0) { if (get_errno() == EAGAIN) { continue; } ndbg("sendDiscover Error\n"); return -1; } ndbg("Waiting Offer...(%d)\n", pdhcpc->sockfd); result = recv(pdhcpc->sockfd, &pdhcpc->packet, sizeof(struct dhcp_msg), 0); ndbg("Received...(%d)\n", result); if (result <= 0) { ndbg("receive fail\n"); continue; } msgtype = dhcpc_parsemsg(pdhcpc, result, presult); if (msgtype == DHCPOFFER) { /* Save the servid from the presult so that it is not clobbered * by a new OFFER. */ ndbg("Received OFFER from %08x\n", ntohl(presult->serverid.s_addr)); pdhcpc->ipaddr.s_addr = presult->ipaddr.s_addr; pdhcpc->serverid.s_addr = presult->serverid.s_addr; /* Temporarily use the address offered by the server and break * out of the loop. */ ret = netlib_set_ipv4addr(intf, &presult->ipaddr); if (ret == -1) { ndbg("Set IPv4 fail\n"); } g_dhcpc_state = STATE_HAVE_OFFER; break; } else { ndbg("Received AnotherData %d %x\n", result, msgtype); } } while (g_dhcpc_state == STATE_INITIAL); /* Loop sending the REQUEST up to three times (if there is no response) */ retries = 0; /* Send the REQUEST message to obtain the lease that was offered to us. */ ndbg("Send REQUEST\n"); do { if (retries++ > CNT_MAX_REQUEST) break; ndbg("Send Request Packet\n"); result = dhcpc_sendmsg(pdhcpc, g_pResult, DHCPREQUEST); if (result < 0) { ndbg("thread_sendRequest Error\n"); return -3; } usleep(100000); /* Get the ACK/NAK response to the REQUEST (or timeout) */ ndbg("Waiting Ack...\n"); result = recv(pdhcpc->sockfd, &pdhcpc->packet, sizeof(struct dhcp_msg), 0); ndbg("Received...(%d)\n", result); if (result <= 0) { ndbg("recv request error(%d)(%d)\n", result, errno); continue; } /* Parse the response */ ndbg("Data Received\n"); msgtype = dhcpc_parsemsg(pdhcpc, result, presult); /* The ACK response means that the server has accepted our request * and we have the lease. */ if (msgtype == DHCPACK) { ndbg("Received ACK\n"); g_dhcpc_state = STATE_HAVE_LEASE; } /* NAK means the server has refused our request. Break out of * this loop with state == STATE_HAVE_OFFER and send DISCOVER again */ else if (msgtype == DHCPNAK) { ndbg("Received NAK\n"); break; } /* If we get any OFFERs from other servers, then decline them now * and continue waiting for the ACK from the server that we * requested from. */ else if (msgtype == DHCPOFFER) { /* If we get OFFERs from same dhcp server, do not send DECLINE */ if (pdhcpc->serverid.s_addr == presult->serverid.s_addr) { ndbg("Received duplicated OFFER from %08x\n", ntohl(presult->serverid.s_addr)); } else { ndbg("Received another OFFER from %08x, send DECLINE\n", ntohl(presult->serverid.s_addr)); result = dhcpc_sendmsg(pdhcpc, presult, DHCPDECLINE); if (result <= 0) { ndbg("recv request error(%d)(%d)\n", result, errno); } } } /* Otherwise, it is something that we do not recognize */ else { ndbg("Ignoring msgtype=%d %d\n", msgtype, result); } usleep(100000L); /* An error has occurred. If this was a timeout error (meaning * that nothing was received on this socket for a long period of time). * Then break out and send the DISCOVER command again (at most * 3 times). */ } while (g_dhcpc_state == STATE_HAVE_OFFER); ndbg("Got IP address %d.%d.%d.%d\n", (presult->ipaddr.s_addr) & 0xff, (presult->ipaddr.s_addr >> 8) & 0xff, (presult->ipaddr.s_addr >> 16) & 0xff, (presult->ipaddr.s_addr >> 24) & 0xff); ndbg("Got netmask %d.%d.%d.%d\n", (presult->netmask.s_addr) & 0xff, (presult->netmask.s_addr >> 8) & 0xff, (presult->netmask.s_addr >> 16) & 0xff, (presult->netmask.s_addr >> 24) & 0xff); ndbg("Got DNS server %d.%d.%d.%d\n", (presult->dnsaddr.s_addr) & 0xff, (presult->dnsaddr.s_addr >> 8) & 0xff, (presult->dnsaddr.s_addr >> 16) & 0xff, (presult->dnsaddr.s_addr >> 24) & 0xff); ndbg("Got default router %d.%d.%d.%d\n", (presult->default_router.s_addr) & 0xff, (presult->default_router.s_addr >> 8) & 0xff, (presult->default_router.s_addr >> 16) & 0xff, (presult->default_router.s_addr >> 24) & 0xff); ndbg("Lease expires in %d seconds\n", presult->lease_time); #if defined CONFIG_NET_LWIP // this is temporal fix. it should be modified later ip_addr_t dns_addr; IP_SET_TYPE_VAL(dns_addr, IPADDR_TYPE_V4); #ifdef CONFIG_NET_IPv6 dns_addr.u_addr.ip4.addr = presult->dnsaddr.s_addr; #else dns_addr.addr = presult->dnsaddr.s_addr; #endif dns_setserver(0, &dns_addr); #endif /* CONFIG_NET_LWIP */ #if defined(CONFIG_NETDB_DNSCLIENT) && defined(CONFIG_NETDB_DNSSERVER_BY_DHCP) struct sockaddr_in dns; if (presult->dnsaddr.s_addr != 0) { ndbg("Set DNS IP address via dns_add_nameserver\n"); dns.sin_addr.s_addr = presult->dnsaddr.s_addr; dns.sin_family = AF_INET; dns.sin_port = htons(DNS_DEFAULT_PORT); dns_add_nameserver((FAR struct sockaddr *)&dns, sizeof(struct sockaddr_in)); } #endif return OK; }
int dhcpc_request(void *handle, struct dhcpc_state *presult) { struct dhcpc_state_s *pdhcpc = (struct dhcpc_state_s *)handle; struct in_addr oldaddr; struct in_addr newaddr; ssize_t result; uint8_t msgtype; int retries; int state; /* Save the currently assigned IP address (should be INADDR_ANY) */ oldaddr.s_addr = 0; uip_gethostaddr("eth0", &oldaddr); /* Loop until we receive the lease (or an error occurs) */ do { /* Set the IP address to INADDR_ANY. */ newaddr.s_addr = INADDR_ANY; (void)uip_sethostaddr("eth0", &newaddr); /* Loop sending DISCOVER until we receive an OFFER from a DHCP * server. We will lock on to the first OFFER and decline any * subsequent offers (which will happen if there are more than one * DHCP servers on the network. */ state = STATE_INITIAL; do { /* Send the DISCOVER command */ dbg("Broadcast DISCOVER\n"); if (dhcpc_sendmsg(pdhcpc, presult, DHCPDISCOVER) < 0) { return ERROR; } /* Get the DHCPOFFER response */ result = recv(pdhcpc->sockfd, &pdhcpc->packet, sizeof(struct dhcp_msg), 0); if (result >= 0) { msgtype = dhcpc_parsemsg(pdhcpc, result, presult); if (msgtype == DHCPOFFER) { /* Save the servid from the presult so that it is not clobbered * by a new OFFER. */ dbg("Received OFFER from %08x\n", ntohl(presult->serverid.s_addr)); pdhcpc->ipaddr.s_addr = presult->ipaddr.s_addr; pdhcpc->serverid.s_addr = presult->serverid.s_addr; /* Temporarily use the address offered by the server and break * out of the loop. */ (void)uip_sethostaddr("eth0", &presult->ipaddr); state = STATE_HAVE_OFFER; } } /* An error has occurred. If this was a timeout error (meaning that * nothing was received on this socket for a long period of time). * Then loop and send the DISCOVER command again. */ else if (errno != EAGAIN) { /* An error other than a timeout was received -- error out */ return ERROR; } } while (state == STATE_INITIAL); /* Loop sending the REQUEST up to three times (if there is no response) */ retries = 0; do { /* Send the REQUEST message to obtain the lease that was offered to us. */ dbg("Send REQUEST\n"); if (dhcpc_sendmsg(pdhcpc, presult, DHCPREQUEST) < 0) { return ERROR; } retries++; /* Get the ACK/NAK response to the REQUEST (or timeout) */ result = recv(pdhcpc->sockfd, &pdhcpc->packet, sizeof(struct dhcp_msg), 0); if (result >= 0) { /* Parse the response */ msgtype = dhcpc_parsemsg(pdhcpc, result, presult); /* The ACK response means that the server has accepted our request * and we have the lease. */ if (msgtype == DHCPACK) { dbg("Received ACK\n"); state = STATE_HAVE_LEASE; } /* NAK means the server has refused our request. Break out of * this loop with state == STATE_HAVE_OFFER and send DISCOVER again */ else if (msgtype == DHCPNAK) { dbg("Received NAK\n"); break; } /* If we get any OFFERs from other servers, then decline them now * and continue waiting for the ACK from the server that we * requested from. */ else if (msgtype == DHCPOFFER) { dbg("Received another OFFER, send DECLINE\n"); (void)dhcpc_sendmsg(pdhcpc, presult, DHCPDECLINE); } /* Otherwise, it is something that we do not recognize */ else { dbg("Ignoring msgtype=%d\n", msgtype); } } /* An error has occurred. If this was a timeout error (meaning * that nothing was received on this socket for a long period of time). * Then break out and send the DISCOVER command again (at most * 3 times). */ else if (errno != EAGAIN) { /* An error other than a timeout was received */ (void)uip_sethostaddr("eth0", &oldaddr); return ERROR; } } while (state == STATE_HAVE_OFFER && retries < 3); } while (state != STATE_HAVE_LEASE); dbg("Got IP address %d.%d.%d.%d\n", (presult->ipaddr.s_addr >> 24 ) & 0xff, (presult->ipaddr.s_addr >> 16 ) & 0xff, (presult->ipaddr.s_addr >> 8 ) & 0xff, (presult->ipaddr.s_addr ) & 0xff); dbg("Got netmask %d.%d.%d.%d\n", (presult->netmask.s_addr >> 24 ) & 0xff, (presult->netmask.s_addr >> 16 ) & 0xff, (presult->netmask.s_addr >> 8 ) & 0xff, (presult->netmask.s_addr ) & 0xff); dbg("Got DNS server %d.%d.%d.%d\n", (presult->dnsaddr.s_addr >> 24 ) & 0xff, (presult->dnsaddr.s_addr >> 16 ) & 0xff, (presult->dnsaddr.s_addr >> 8 ) & 0xff, (presult->dnsaddr.s_addr ) & 0xff); dbg("Got default router %d.%d.%d.%d\n", (presult->default_router.s_addr >> 24 ) & 0xff, (presult->default_router.s_addr >> 16 ) & 0xff, (presult->default_router.s_addr >> 8 ) & 0xff, (presult->default_router.s_addr ) & 0xff); dbg("Lease expires in %d seconds\n", presult->lease_time); return OK; }