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/>.
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
;
74 dhcp_request_t request
;
79 request
.buffer
= kmalloc (DHCP_REQUEST_MAX_LEN
);
84 char *buffer
= kmalloc (1024);
87 kfree (request
.buffer
);
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;
100 /* Create a socket */
101 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
102 kprintf ("DHCP client -> Can't create socket.\n");
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");
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
,
130 memcpy (buffer
+ 1, netif
->dev
->dev_addr
, 6);
131 pos
= dhcp_request_option_add (request
, DHCP_OPTION_CLIENT_IDENTIFIER
,
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
,
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");
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");
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
);
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
) {
186 if (request
.buffer
[pos
] == DHCP_OPTION_END
)
189 if (pos
>= recv_ret
- 2) {
194 option_len
= request
.buffer
[pos
+ 1];
197 if (pos
+ option_len
>= recv_ret
) {
202 switch (request
.buffer
[pos
- 2]) {
203 case DHCP_OPTION_SUBNET_MASK
:
205 memcpy (&config_mask
, request
.buffer
+ pos
, sizeof (net_ipv4
));
207 case DHCP_OPTION_ROUTER
:
209 memcpy (&config_gw
, request
.buffer
+ pos
, sizeof (net_ipv4
));
211 case DHCP_OPTION_DNS_SERVER
:
213 memcpy (&config_dns
, request
.buffer
+ pos
, sizeof (net_ipv4
));
215 case DHCP_OPTION_DHCP_SERVER
:
217 memcpy (&config_dhcp
, request
.buffer
+ pos
, sizeof (net_ipv4
));
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
,
235 memcpy (buffer
, &config_ip
, 4);
236 pos
= dhcp_request_option_add (request
, DHCP_OPTION_REQUESTED_IP
,
239 memcpy (buffer
, &config_dhcp
, 4);
240 pos
= dhcp_request_option_add (request
, DHCP_OPTION_DHCP_SERVER
,
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");
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");
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
);
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
) {
275 if (request
.buffer
[pos
] == DHCP_OPTION_END
)
278 if (pos
>= recv_ret
- 2) {
283 option_len
= request
.buffer
[pos
+ 1];
286 if (pos
+ option_len
>= recv_ret
) {
291 switch (request
.buffer
[pos
- 2]) {
292 case DHCP_OPTION_SUBNET_MASK
:
294 memcpy (&config_mask
, request
.buffer
+ pos
, sizeof (net_ipv4
));
296 case DHCP_OPTION_ROUTER
:
298 memcpy (&config_gw
, request
.buffer
+ pos
, sizeof (net_ipv4
));
300 case DHCP_OPTION_DNS_SERVER
:
302 memcpy (&config_dns
, request
.buffer
+ pos
, sizeof (net_ipv4
));
304 case DHCP_OPTION_DHCP_SERVER
:
306 memcpy (&config_dhcp
, request
.buffer
+ pos
, sizeof (net_ipv4
));
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
);
324 dns_addr (config_dns
);
325 netif_ip_addr (netif
, config_ip
, IF_CFG_TYPE_DHCP
);
326 netif_gw_addr (netif
, config_gw
);
329 kfree (request
.buffer
);