3 * Copyright (C) 2009 Martin 'povik' Poviser (martin.povik@gmail.com)
4 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
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/>.
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
,
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
;
75 dhcp_request_t request
;
80 request
.buffer
= kmalloc (DHCP_REQUEST_MAX_LEN
);
85 char *buffer
= kmalloc (1024);
88 kfree (request
.buffer
);
92 net_ipv4 config_gw
= 0x00000000;
93 net_ipv4 config_ip
= 0x00000000;
94 net_ipv4 config_dns
= 0x00000000;
95 net_ipv4 config_mask
= 0x00000000;
96 net_ipv4 config_dhcp
= 0x00000000;
97 unsigned int config_lease_time
= 0;
101 /* Create a socket */
102 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
103 kprintf ("DHCP client -> Can't create socket.\n");
104 ret
= DHCP_SOCKET_FAILED
;
108 server_socket
.sin_family
= AF_INET
;
109 server_socket
.sin_port
= htons (67);
110 memcpy (&(server_socket
.sin_addr
), &server_addr
, sizeof (net_ipv4
));
112 /* Let's connect to server */
113 if (connect (sock
, (sockaddr
*) &server_socket
,
114 sizeof (server_socket
)) == -1) {
115 kprintf ("DHCP client -> Connection can't be estabilished\n");
116 ret
= DHCP_CONNECT_FAILED
;
120 net_proto_udp_anycast (sock
);
121 net_proto_udp_port (sock
, htons (68));
123 pos
= dhcp_request_header_prepare (request
, netif
,
124 DHCP_MESSAGE_TYPE_BOOTREQUEST
);
125 xid
= request
.bootp_header
->xid
;
127 buffer
[0] = DHCP_OPTION_VALUE_DHCPDISCOVER
;
128 pos
= dhcp_request_option_add (request
, DHCP_OPTION_MESSAGE_TYPE
,
132 memcpy (buffer
+ 1, netif
->dev
->dev_addr
, 6);
133 pos
= dhcp_request_option_add (request
, DHCP_OPTION_CLIENT_IDENTIFIER
,
136 char *hostname
= hostname_get ();
138 if (strlen (hostname
) <= 128) {
139 unsigned host_len
= strlen (hostname
);
140 pos
= dhcp_request_option_add (request
, DHCP_OPTION_HOSTNAME
,
141 buffer
, host_len
, pos
);
144 buffer
[0] = DHCP_OPTION_VALUE_SUBNET_MASK
;
145 buffer
[1] = DHCP_OPTION_VALUE_ROUTER
;
146 buffer
[2] = DHCP_OPTION_VALUE_DNS_SERVER
;
147 buffer
[3] = DHCP_OPTION_VALUE_DOMAIN_NAME
;
148 pos
= dhcp_request_option_add (request
, DHCP_OPTION_PARAMETER_REQUEST_LIST
,
153 kprintf ("DHCP client -> sending request\n");
154 if (send (sock
, request
.buffer
, pos
, 0) < 0) {
155 kprintf ("DHCP client -> Can't send request.\n");
156 ret
= DHCP_CANT_SEND_REQUEST
;
159 kprintf ("DHCP client -> reuquest sended\n");
162 config_ip
= 0x00000000;
163 config_gw
= 0x00000000;
164 config_dns
= 0x00000000;
165 config_dhcp
= 0x00000000;
167 kprintf ("DHCP client -> receiving response\n");
168 if ((recv_ret
= recv (sock
, request
.buffer
, DHCP_REQUEST_MAX_LEN
, 0)) < sizeof (dhcp_bootp_header_t
)) {
169 kprintf ("DHCP client -> Can't receive response.\n");
170 ret
= DHCP_CANT_RECV_RESPONSE
;
173 kprintf ("DHCP client -> response received\n");
175 if (request
.bootp_header
->mag_cookie
!= DHCP_MAGIC_COOKIE
) {
176 kprintf ("DHCP client -> bad magic (finded 0x%X - needed 0x%X\n",
177 request
.bootp_header
->mag_cookie
, DHCP_MAGIC_COOKIE
);
178 ret
= DHCP_BAD_PACKET
;
182 pos
= sizeof (dhcp_bootp_header_t
);
184 config_ip
= request
.bootp_header
->yiaddr
;
186 if (request
.bootp_header
->xid
!= xid
) {
187 kprintf ("DHCP client -> bad xid");
192 while (pos
< recv_ret
) {
193 unsigned int option_len
;
195 if (request
.buffer
[pos
] == DHCP_OPTION_PAD
) {
200 if (request
.buffer
[pos
] == DHCP_OPTION_END
)
203 if (pos
>= recv_ret
- 2) {
204 ret
= DHCP_BAD_PACKET
;
208 option_len
= request
.buffer
[pos
+ 1];
211 if (pos
+ option_len
>= recv_ret
) {
212 ret
= DHCP_BAD_PACKET
;
215 switch (request
.buffer
[pos
- 2]) {
216 case DHCP_OPTION_MESSAGE_TYPE
:
217 if (!option_len
== 1) {
218 ret
= DHCP_BAD_PACKET
;
221 switch (request
.buffer
[pos
]) {
222 case DHCP_OPTION_VALUE_DHCPOFFER
:
224 case DHCP_OPTION_VALUE_DHCPACK
:
227 case DHCP_OPTION_VALUE_DHCPNAK
:
228 ret
= DHCP_SRV_DIDNT_UNDERSTAND
;
232 kprintf ("DHCP client -> bad DHCP message type");
236 case DHCP_OPTION_SUBNET_MASK
:
238 memcpy (&config_mask
, request
.buffer
+ pos
, sizeof (net_ipv4
));
240 case DHCP_OPTION_ROUTER
:
242 memcpy (&config_gw
, request
.buffer
+ pos
, sizeof (net_ipv4
));
244 case DHCP_OPTION_DNS_SERVER
:
246 memcpy (&config_dns
, request
.buffer
+ pos
, sizeof (net_ipv4
));
248 case DHCP_OPTION_DHCP_SERVER
:
250 memcpy (&config_dhcp
, request
.buffer
+ pos
, sizeof (net_ipv4
));
259 kprintf ("DHCP client -> response parsed\n");
264 pos
= dhcp_request_header_prepare (request
, netif
,
265 DHCP_MESSAGE_TYPE_BOOTREQUEST
);
267 buffer
[0] = DHCP_OPTION_VALUE_DHCPREQUEST
;
268 pos
= dhcp_request_option_add (request
, DHCP_OPTION_MESSAGE_TYPE
,
271 memcpy (buffer
, &config_ip
, 4);
272 pos
= dhcp_request_option_add (request
, DHCP_OPTION_REQUESTED_IP
,
275 memcpy (buffer
, &config_dhcp
, 4);
276 pos
= dhcp_request_option_add (request
, DHCP_OPTION_DHCP_SERVER
,
279 kprintf ("DHCP client -> sending request\n");
280 if (send (sock
, request
.buffer
, pos
, 0) < 0) {
281 kprintf ("DHCP client -> Can't send request.\n");
282 ret
= DHCP_CANT_SEND_REQUEST
;
285 kprintf ("DHCP client -> request sended\n");
289 kprintf ("DHCP client -> receiving response\n");
290 if ((recv_ret
= recv (sock
, request
.buffer
, DHCP_REQUEST_MAX_LEN
, 0)) < sizeof (dhcp_bootp_header_t
)) {
291 kprintf ("DHCP client -> Can't receive response.\n");
292 ret
= DHCP_CANT_RECV_RESPONSE
;
295 kprintf ("DHCP client -> response received\n");
297 if (request
.bootp_header
->mag_cookie
!= DHCP_MAGIC_COOKIE
) {
298 kprintf ("DHCP client -> bad magic (finded 0x%X - needed 0x%X\n",
299 request
.bootp_header
->mag_cookie
, DHCP_MAGIC_COOKIE
);
300 ret
= DHCP_BAD_PACKET
;
304 if (request
.bootp_header
->xid
!= xid
) {
305 kprintf ("DHCP client -> bad xid");
309 pos
= sizeof (dhcp_bootp_header_t
);
311 while (pos
< recv_ret
) {
312 unsigned int option_len
;
313 if (request
.buffer
[pos
] == DHCP_OPTION_PAD
) {
318 if (request
.buffer
[pos
] == DHCP_OPTION_END
)
321 if (pos
>= recv_ret
- 2) {
322 ret
= DHCP_BAD_PACKET
;
326 option_len
= request
.buffer
[pos
+ 1];
329 if (pos
+ option_len
>= recv_ret
) {
330 ret
= DHCP_BAD_PACKET
;
334 switch (request
.buffer
[pos
- 2]) {
335 case DHCP_OPTION_MESSAGE_TYPE
:
336 if (!option_len
== 1) {
337 ret
= DHCP_BAD_PACKET
;
340 switch (request
.buffer
[pos
]) {
341 case DHCP_OPTION_VALUE_DHCPOFFER
:
342 ret
= DHCP_BAD_PACKET
;
345 case DHCP_OPTION_VALUE_DHCPACK
:
347 case DHCP_OPTION_VALUE_DHCPNAK
:
348 ret
= DHCP_SRV_DIDNT_UNDERSTAND
;
352 kprintf ("DHCP client -> bad DHCP message type");
356 case DHCP_OPTION_SUBNET_MASK
:
358 memcpy (&config_mask
, request
.buffer
+ pos
, sizeof (net_ipv4
));
360 case DHCP_OPTION_ROUTER
:
362 memcpy (&config_gw
, request
.buffer
+ pos
, sizeof (net_ipv4
));
364 case DHCP_OPTION_DNS_SERVER
:
366 memcpy (&config_dns
, request
.buffer
+ pos
, sizeof (net_ipv4
));
376 kprintf ("DHCP client -> configuring interface\n");
377 kprintf ("DHCP client -> my IP: ");
378 net_proto_ip_print (config_ip
);
379 kprintf ("\nDHCP client -> router IP: ");
380 net_proto_ip_print (config_gw
);
381 kprintf ("\nDHCP client -> DNS server IP: ");
382 net_proto_ip_print (config_dns
);
385 dns_addr (config_dns
);
386 netif_ip_addr (netif
, config_ip
, IF_CFG_TYPE_DHCP
);
387 netif_gw_addr (netif
, config_gw
);
390 kfree (request
.buffer
);