uint8_t dhcp_get_ip() { uint8_t sockid = SOCKET_INVALID; // First get a socket sockid = udp_open(DHCP_CLIENT_PORT); if (sockid == SOCKET_INVALID) return 1; dhcp_send_packet(sockid, DHCP_DISCOVER); if (dhcp_read_packet(sockid) != DHCP_OFFER) return 2; dhcp_send_packet(sockid, DHCP_REQUEST); if (dhcp_read_packet(sockid) != DHCP_ACK) return 3; // Finally close the socket udp_close(sockid); return 0; }
int dhcp_request(uip_ipaddr_t *next_ip, uip_ipaddr_t *server_ip, const char **bootfile) { DhcpPacket out, in; uint8_t byte; uint8_t *options; int remaining; uint8_t requested[] = { DhcpTagSubnetMask, DhcpTagDefaultRouter }; assert(DhcpMaxPacketSize >= DhcpMinPacketSize); uint16_t max_size = htonw(DhcpMaxPacketSize); uint8_t client_id[1 + sizeof(uip_ethaddr)]; client_id[0] = DhcpEthernet; memcpy(client_id + 1, &uip_ethaddr, sizeof(uip_ethaddr)); // Set up the UDP connection. uip_ipaddr_t addr; uip_ipaddr(&addr, 255,255,255,255); struct uip_udp_conn *conn = uip_udp_new(&addr, htonw(DhcpServerPort)); if (!conn) { printf("Failed to set up UDP connection.\n"); return 1; } uip_udp_bind(conn, htonw(DhcpClientPort)); // Send a DHCP discover packet. dhcp_prep_packet(&out, rand()); options = out.options; remaining = sizeof(out.options); byte = DhcpDiscover; dhcp_add_option(&options, DhcpTagMessageType, &byte, sizeof(byte), &remaining); dhcp_add_option(&options, DhcpTagClientIdentifier, client_id, sizeof(client_id), &remaining); dhcp_add_option(&options, DhcpTagParameterRequestList, requested, sizeof(requested), &remaining); dhcp_add_option(&options, DhcpTagMaximumDhcpMessageSize, &max_size, sizeof(max_size), &remaining); dhcp_add_option(&options, DhcpTagEndOfList, NULL, 0, &remaining); dhcp_send_packet(conn, "DHCP discover", &out, &in); // Extract the DHCP server id. uint32_t server_id; if (dhcp_process_options(&in, OptionOverloadNone, &dhcp_get_server, &server_id)) { printf("Failed to extract server id.\n"); return 1; } // We got an offer. Request it. dhcp_state = DhcpRequesting; dhcp_prep_packet(&out, rand()); options = out.options; remaining = sizeof(out.options); byte = DhcpRequest; dhcp_add_option(&options, DhcpTagMessageType, &byte, sizeof(byte), &remaining); dhcp_add_option(&options, DhcpTagClientIdentifier, client_id, sizeof(client_id), &remaining); dhcp_add_option(&options, DhcpTagRequestedIpAddress, &in.your_ip, sizeof(in.your_ip), &remaining); dhcp_add_option(&options, DhcpTagParameterRequestList, requested, sizeof(requested), &remaining); dhcp_add_option(&options, DhcpTagMaximumDhcpMessageSize, &max_size, sizeof(max_size), &remaining); dhcp_add_option(&options, DhcpTagServerIdentifier, &server_id, sizeof(server_id), &remaining); dhcp_add_option(&options, DhcpTagEndOfList, NULL, 0, &remaining); dhcp_send_packet(conn, "DHCP request", &out, &in); DhcpMessageType type; if (dhcp_process_options(&in, OptionOverloadNone, &dhcp_get_type, &type)) { printf("Failed to extract message type.\n"); dhcp_state = DhcpInit; return 1; } if (type == DhcpNak) { printf("DHCP request nak-ed by the server.\n"); dhcp_state = DhcpInit; return 1; } // The server acked, completing the transaction. dhcp_state = DhcpBound; uip_udp_remove(conn); // Apply the settings. if (dhcp_process_options(&in, OptionOverloadNone, &dhcp_apply_options, NULL)) { dhcp_state = DhcpInit; return 1; } int bootfile_size = sizeof(in.bootfile_name) + 1; char *file = xmalloc(bootfile_size); file[bootfile_size - 1] = 0; memcpy(file, in.bootfile_name, sizeof(in.bootfile_name)); *bootfile = file; uip_ipaddr(next_ip, in.server_ip >> 0, in.server_ip >> 8, in.server_ip >> 16, in.server_ip >> 24); uip_ipaddr(server_ip, server_id >> 0, server_id >> 8, server_id >> 16, server_id >> 24); uip_ipaddr_t my_ip; uip_ipaddr(&my_ip, in.your_ip >> 0, in.your_ip >> 8, in.your_ip >> 16, in.your_ip >> 24); uip_sethostaddr(&my_ip); return 0; }