001 // vim: set ft=c: 002 003 #include "::/Adam/Net/Dhcp" 004 005 #define CLIENT_START 0 006 #define CLIENT_DISCOVER 1 007 #define CLIENT_REQUEST 2 008 #define CLIENT_REQUEST_ACCEPTED 3 009 010 #define DHCP_TIMEOUT 3000 011 #define MAX_RETRIES 3 012 013 I64 DhcpConfigureInner(I64 sock, U32* yiaddr_out, U32* dns_ip_out, U32* router_ip_out, U32* subnet_mask_out) { 014 I64 state = CLIENT_START; 015 I64 retries = 0; 016 017 I64 timeout = DHCP_TIMEOUT; 018 019 if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO_MS, &timeout, sizeof(timeout)) < 0) { 020 "DhcpConfigure: setsockopt failed\n"; 021 } 022 023 sockaddr_in addr; 024 addr.sin_family = AF_INET; 025 addr.sin_port = htons(68); 026 addr.sin_addr.s_addr = INADDR_ANY; 027 028 if (bind(sock, &addr, sizeof(addr)) < 0) { 029 "DhcpConfigure: failed to bind\n"; 030 return -1; 031 } 032 033 U32 xid = DhcpBeginTransaction(); 034 035 I64 error = 0; 036 037 U32 dhcp_addr; 038 U8 buffer[2048]; 039 040 I64 count; 041 sockaddr_in addr_in; 042 043 while (state != CLIENT_REQUEST_ACCEPTED) { 044 if (state == CLIENT_START) { 045 state = CLIENT_DISCOVER; 046 retries = 0; 047 } 048 else if (state == CLIENT_DISCOVER) { 049 error = DhcpSendDiscover(xid); 050 if (error < 0) return error; 051 052 count = recvfrom(sock, buffer, sizeof(buffer), 0, &addr_in, sizeof(addr_in)); 053 054 if (count > 0) { 055 //"Try parse Offer\n"; 056 error = DhcpParseOffer(xid, buffer, count, yiaddr_out, dns_ip_out, router_ip_out, subnet_mask_out); 057 058 if (error < 0) { 059 "DhcpParseOffer: error %d\n", error; 060 } 061 } 062 063 if (count > 0 && error >= 0) { 064 dhcp_addr = ntohl(addr_in.sin_addr.s_addr); 065 //"DHCP Offer from %08X: YIAddr %08X,\n\tDNS %08X, Router %08X, Subnet %08X\n", 066 // dhcp_addr, *yiaddr_out, dns_ip, router_ip, subnet_mask; 067 068 state = CLIENT_REQUEST; 069 retries = 0; 070 } 071 else if (++retries == MAX_RETRIES) { 072 "DhcpConfigure: max retries for DISCOVER\n"; 073 return -1; 074 } 075 } 076 else if (state == CLIENT_REQUEST) { 077 error = DhcpSendRequest(xid, *yiaddr_out, dhcp_addr); 078 if (error < 0) return error; 079 080 count = recvfrom(sock, buffer, sizeof(buffer), 0, &addr_in, sizeof(addr_in)); 081 082 if (count > 0) { 083 //"Try parse Ack\n"; 084 error = DhcpParseAck(xid, buffer, count); 085 086 if (error < 0) { 087 "DhcpParseOffer: error %d\n", error; 088 } 089 } 090 091 if (count > 0 && error >= 0) { 092 dhcp_addr = ntohl(addr_in.sin_addr.s_addr); 093 //"DHCP Ack from %08X\n", dhcp_addr; 094 095 state = CLIENT_REQUEST_ACCEPTED; 096 } 097 else if (++retries == MAX_RETRIES) { 098 "DhcpConfigure: max retries for REQUEST\n"; 099 return -1; 100 } 101 } 102 } 103 104 return state; 105 } 106 107 I64 DhcpConfigure() { 108 I64 sock = socket(AF_INET, SOCK_DGRAM); 109 110 if (sock < 0) 111 return -1; 112 113 U32 yiaddr, dns_ip, router_ip, subnet_mask; 114 I64 state = DhcpConfigureInner(sock, &yiaddr, &dns_ip, &router_ip, &subnet_mask); 115 116 close(sock); 117 118 if (state == CLIENT_REQUEST_ACCEPTED) { 119 in_addr in; 120 in.s_addr = htonl(yiaddr); 121 "Obtained IP address %s\n", inet_ntoa(in); 122 IPv4SetAddress(yiaddr); 123 IPv4SetSubnet(router_ip, subnet_mask); 124 DnsSetResolverIPv4(dns_ip); 125 return 0; 126 } 127 else 128 return -1; 129 } 130 131 U0 Netcfg() { 132 SocketInit(); 133 134 "Netcfg: Configuring network...\n"; 135 136 I64 error = DhcpConfigure(); 137 if (error < 0) 138 "DhcpConfigure: error %d\n", error; 139 }