Cleanup in elf.c with .bss section clean; adm command mounts cdrom instead of floppy...
[ZeXOS.git] / kernel / core / net / dhcp.c
blob530725161eda188d944a58616bbedd3b266250bf
1 /*
2 * ZeX/OS
3 * Copyright (C) 2009 Martin 'povik' Poviser (martin.povik@gmail.com)
4 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
21 #include <system.h>
22 #include <string.h>
23 #include <net/if.h>
24 #include <net/ip.h>
25 #include <net/dhcp.h>
26 #include <net/socket.h>
27 #include <net/hostname.h>
29 #define DHCP_REQUEST_MAX_LEN 4096
31 int dhcp_request_header_prepare (dhcp_request_t request, netif_t *netif,
32 char req_type)
34 request.bootp_header->op = req_type; /* Request type */
35 request.bootp_header->htype = 0x01; /* Connection type : Ethernet */ /* TODO */
36 request.bootp_header->hlen = 0x06; /* Hardware address length : 6 bytes */
37 request.bootp_header->hops = 0x00; /* Clients set to zero */
38 request.bootp_header->xid = 0x12345678; /* Random request ID */
39 request.bootp_header->secs = 0x0000; /* Is'nt needed in dhcp request */
40 request.bootp_header->flags = 0x0000; /* No flags */
42 request.bootp_header->ciaddr = NET_IPV4_TO_ADDR (0, 0, 0, 0);
43 request.bootp_header->yiaddr = NET_IPV4_TO_ADDR (0, 0, 0, 0);
44 request.bootp_header->siaddr = NET_IPV4_TO_ADDR (0, 0, 0, 0);
45 request.bootp_header->giaddr = NET_IPV4_TO_ADDR (0, 0, 0, 0);
47 memcpy (request.bootp_header->chaddr, netif->dev->dev_addr, 6);
49 request.bootp_header->sname[0] = 0;
50 request.bootp_header->file[0] = 0;
52 request.bootp_header->mag_cookie = DHCP_MAGIC_COOKIE;
54 return sizeof (dhcp_bootp_header_t);
57 int dhcp_request_option_add (dhcp_request_t request, char option_type, char *buffer,
58 int buffer_len, int pos)
60 request.buffer[pos] = option_type;
61 request.buffer[pos + 1] = buffer_len;
62 memcpy (request.buffer + pos + 2, buffer, buffer_len);
64 return pos + 2 + buffer_len;
67 int dhcp_config_if (netif_t *netif)
69 net_ipv4 server_addr = INADDR_BROADCAST;
70 sockaddr_in server_socket;
71 int sock = 0;
73 unsigned int pos;
74 dhcp_request_t request;
76 if (!netif)
77 return -1;
79 request.buffer = kmalloc (DHCP_REQUEST_MAX_LEN);
81 if (!request.buffer)
82 return -2;
84 char *buffer = kmalloc (1024);
86 if (!buffer) {
87 kfree (request.buffer);
88 return -2;
91 net_ipv4 config_gw = 0x00000000;
92 net_ipv4 config_ip = 0x00000000;
93 net_ipv4 config_dns = 0x00000000;
94 net_ipv4 config_mask = 0x00000000;
95 net_ipv4 config_dhcp = 0x00000000;
96 unsigned int config_lease_time = 0;
98 int ret = 0;
100 /* Create a socket */
101 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
102 kprintf ("DHCP client -> Can't create socket.\n");
103 ret = -3;
104 goto clear;
107 server_socket.sin_family = AF_INET;
108 server_socket.sin_port = htons (67);
109 memcpy (&(server_socket.sin_addr), &server_addr, sizeof (net_ipv4));
111 /* Let's connect to server */
112 if (connect (sock, (sockaddr *) &server_socket,
113 sizeof (server_socket)) == -1) {
114 kprintf ("DHCP client -> Connection can't be estabilished\n");
115 ret = -4;
116 goto clear;
119 net_proto_udp_anycast (sock);
120 net_proto_udp_port (sock, htons (68));
122 pos = dhcp_request_header_prepare (request, netif,
123 DHCP_MESSAGE_TYPE_BOOTREQUEST);
125 buffer[0] = DHCP_OPTION_VALUE_DHCPDISCOVER;
126 pos = dhcp_request_option_add (request, DHCP_OPTION_MESSAGE_TYPE,
127 buffer, 1, pos);
129 buffer[0] = 0x01;
130 memcpy (buffer + 1, netif->dev->dev_addr, 6);
131 pos = dhcp_request_option_add (request, DHCP_OPTION_CLIENT_IDENTIFIER,
132 buffer, 7, pos);
134 char *hostname = hostname_get ();
136 if (strlen (hostname) <= 128) {
137 unsigned host_len = strlen (hostname);
138 pos = dhcp_request_option_add (request, DHCP_OPTION_HOSTNAME,
139 buffer, host_len, pos);
142 buffer[0] = DHCP_OPTION_VALUE_SUBNET_MASK;
143 buffer[1] = DHCP_OPTION_VALUE_ROUTER;
144 buffer[2] = DHCP_OPTION_VALUE_DNS_SERVER;
145 buffer[3] = DHCP_OPTION_VALUE_DOMAIN_NAME;
146 pos = dhcp_request_option_add (request, DHCP_OPTION_PARAMETER_REQUEST_LIST,
147 buffer, 0x04, pos);
149 int recv_ret;
151 kprintf ("DHCP client -> sending request\n");
152 if (send (sock, request.buffer, pos, 0) < 0) {
153 kprintf ("DHCP client -> Can't send request.\n");
154 ret = -5;
155 goto clear;
157 kprintf ("DHCP client -> reuquest sended\n");
159 kprintf ("DHCP client -> receiving response\n");
160 if ((recv_ret = recv (sock, request.buffer, DHCP_REQUEST_MAX_LEN, 0)) < sizeof (dhcp_bootp_header_t)) {
161 kprintf ("DHCP client -> Can't receive response.\n");
162 ret = -6;
163 goto clear;
165 kprintf ("DHCP client -> response received\n");
167 if (request.bootp_header->mag_cookie != DHCP_MAGIC_COOKIE) {
168 kprintf ("DHCP client -> bad magic (finded 0x%X - needed 0x%X\n",
169 request.bootp_header->mag_cookie, DHCP_MAGIC_COOKIE);
170 ret = -7;
171 goto clear;
174 pos = sizeof (dhcp_bootp_header_t);
176 config_ip = request.bootp_header->yiaddr;
178 while (pos < recv_ret) {
179 unsigned int option_len;
181 if (request.buffer[pos] == DHCP_OPTION_PAD) {
182 pos += 1;
183 continue;
186 if (request.buffer[pos] == DHCP_OPTION_END)
187 break;
189 if (pos >= recv_ret - 2) {
190 ret = -8;
191 goto clear;
194 option_len = request.buffer[pos + 1];
195 pos += 2;
197 if (pos + option_len >= recv_ret) {
198 ret = -8;
199 goto clear;
202 switch (request.buffer[pos - 2]) {
203 case DHCP_OPTION_SUBNET_MASK:
204 if (option_len >= 4)
205 memcpy (&config_mask, request.buffer + pos, sizeof (net_ipv4));
206 break;
207 case DHCP_OPTION_ROUTER:
208 if (option_len >= 4)
209 memcpy (&config_gw, request.buffer + pos, sizeof (net_ipv4));
210 break;
211 case DHCP_OPTION_DNS_SERVER:
212 if (option_len >= 4)
213 memcpy (&config_dns, request.buffer + pos, sizeof (net_ipv4));
214 break;
215 case DHCP_OPTION_DHCP_SERVER:
216 if (option_len >= 4)
217 memcpy (&config_dhcp, request.buffer + pos, sizeof (net_ipv4));
218 break;
219 default:
220 break;
223 pos += option_len;
226 kprintf ("DHCP client -> response parsed\n");
228 pos = dhcp_request_header_prepare (request, netif,
229 DHCP_MESSAGE_TYPE_BOOTREQUEST);
231 buffer[0] = DHCP_OPTION_VALUE_DHCPREQUEST;
232 pos = dhcp_request_option_add (request, DHCP_OPTION_MESSAGE_TYPE,
233 buffer, 1, pos);
235 memcpy (buffer, &config_ip, 4);
236 pos = dhcp_request_option_add (request, DHCP_OPTION_REQUESTED_IP,
237 buffer, 4, pos);
239 memcpy (buffer, &config_dhcp, 4);
240 pos = dhcp_request_option_add (request, DHCP_OPTION_DHCP_SERVER,
241 buffer, 4, pos);
243 kprintf ("DHCP client -> sending request\n");
244 if (send (sock, request.buffer, pos, 0) < 0) {
245 kprintf ("DHCP client -> Can't send request.\n");
246 ret = -5;
247 goto clear;
249 kprintf ("DHCP client -> request sended\n");
251 kprintf ("DHCP client -> receiving response\n");
252 if ((recv_ret = recv (sock, request.buffer, DHCP_REQUEST_MAX_LEN, 0)) < sizeof (dhcp_bootp_header_t)) {
253 kprintf ("DHCP client -> Can't receive response.\n");
254 ret = -6;
255 goto clear;
257 kprintf ("DHCP client -> response received\n");
259 if (request.bootp_header->mag_cookie != DHCP_MAGIC_COOKIE) {
260 kprintf ("DHCP client -> bad magic (finded 0x%X - needed 0x%X\n",
261 request.bootp_header->mag_cookie, DHCP_MAGIC_COOKIE);
262 ret = -7;
263 goto clear;
266 pos = sizeof (dhcp_bootp_header_t);
268 while (pos < recv_ret) {
269 unsigned int option_len;
270 if (request.buffer[pos] == DHCP_OPTION_PAD) {
271 pos += 1;
272 continue;
275 if (request.buffer[pos] == DHCP_OPTION_END)
276 break;
278 if (pos >= recv_ret - 2) {
279 ret = -8;
280 goto clear;
283 option_len = request.buffer[pos + 1];
284 pos += 2;
286 if (pos + option_len >= recv_ret) {
287 ret = -8;
288 goto clear;
291 switch (request.buffer[pos - 2]) {
292 case DHCP_OPTION_SUBNET_MASK:
293 if (option_len >= 4)
294 memcpy (&config_mask, request.buffer + pos, sizeof (net_ipv4));
295 break;
296 case DHCP_OPTION_ROUTER:
297 if (option_len >= 4)
298 memcpy (&config_gw, request.buffer + pos, sizeof (net_ipv4));
299 break;
300 case DHCP_OPTION_DNS_SERVER:
301 if (option_len >= 4)
302 memcpy (&config_dns, request.buffer + pos, sizeof (net_ipv4));
303 break;
304 case DHCP_OPTION_DHCP_SERVER:
305 if (option_len >= 4)
306 memcpy (&config_dhcp, request.buffer + pos, sizeof (net_ipv4));
307 break;
308 default:
309 break;
312 pos += option_len;
315 kprintf ("DHCP client -> configuring interface\n");
316 kprintf ("DHCP client -> my IP: ");
317 net_proto_ip_print (config_ip);
318 kprintf ("\nDHCP client -> router IP: ");
319 net_proto_ip_print (config_gw);
320 kprintf ("\nDHCP client -> DNS server IP: ");
321 net_proto_ip_print (config_dns);
322 kprintf ("\n");
324 dns_addr (config_dns);
325 netif_ip_addr (netif, config_ip, IF_CFG_TYPE_DHCP);
326 netif_gw_addr (netif, config_gw);
327 clear:
328 kfree (buffer);
329 kfree (request.buffer);
330 sclose (sock);
332 return ret;