3 * Copyright (C) 2009 Martin 'povik' Poviser (martin.povik@gmail.com)
4 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * Copyright (C) 2010 Martin 'povik' Poviser (martin.povik@gmail.com)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <net/socket.h>
28 #include <net/hostname.h>
30 #define DHCP_REQUEST_MAX_LEN 4096
32 int dhcp_request_header_prepare (dhcp_request_t request
, netif_t
*netif
,
35 request
.bootp_header
->op
= req_type
; /* Request type */
36 request
.bootp_header
->htype
= 0x01; /* Connection type : Ethernet */ /* TODO */
37 request
.bootp_header
->hlen
= 0x06; /* Hardware address length : 6 bytes */
38 request
.bootp_header
->hops
= 0x00; /* Clients set to zero */
39 request
.bootp_header
->xid
= 0x12345678; /* Random request ID */
40 request
.bootp_header
->secs
= 0x0000; /* Is'nt needed in dhcp request */
41 request
.bootp_header
->flags
= 0x0000; /* No flags */
43 request
.bootp_header
->ciaddr
= NET_IPV4_TO_ADDR (0, 0, 0, 0);
44 request
.bootp_header
->yiaddr
= NET_IPV4_TO_ADDR (0, 0, 0, 0);
45 request
.bootp_header
->siaddr
= NET_IPV4_TO_ADDR (0, 0, 0, 0);
46 request
.bootp_header
->giaddr
= NET_IPV4_TO_ADDR (0, 0, 0, 0);
48 memcpy (request
.bootp_header
->chaddr
, netif
->dev
->dev_addr
, 6);
50 request
.bootp_header
->sname
[0] = 0;
51 request
.bootp_header
->file
[0] = 0;
53 request
.bootp_header
->mag_cookie
= DHCP_MAGIC_COOKIE
;
55 return sizeof (dhcp_bootp_header_t
);
58 int dhcp_request_option_add (dhcp_request_t request
, char option_type
, char *buffer
,
59 int buffer_len
, int pos
)
61 request
.buffer
[pos
] = option_type
;
62 request
.buffer
[pos
+ 1] = buffer_len
;
63 memcpy (request
.buffer
+ pos
+ 2, buffer
, buffer_len
);
65 return pos
+ 2 + buffer_len
;
68 int dhcp_config_if (netif_t
*netif
)
70 net_ipv4 server_addr
= INADDR_BROADCAST
;
71 sockaddr_in server_socket
;
76 dhcp_request_t request
;
79 return DHCP_BAD_PARAMETERS
;
81 request
.buffer
= kmalloc (DHCP_REQUEST_MAX_LEN
);
84 return DHCP_OUT_OF_MEMORY
;
86 char *buffer
= kmalloc (1024);
89 kfree (request
.buffer
);
90 return DHCP_OUT_OF_MEMORY
;
93 net_ipv4 config_gw
= 0x00000000;
94 net_ipv4 config_ip
= 0x00000000;
95 net_ipv4 config_dns
= 0x00000000;
96 net_ipv4 config_mask
= 0x00000000;
97 net_ipv4 config_dhcp
= 0x00000000;
98 unsigned int config_lease_time
= 0;
102 /* Create a socket */
103 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
104 DPRINT (DBG_DHCP
, "DHCP client -> Can't create socket.");
105 ret
= DHCP_SOCKET_FAILED
;
109 server_socket
.sin_family
= AF_INET
;
110 server_socket
.sin_port
= htons (67);
111 memcpy (&(server_socket
.sin_addr
), &server_addr
, sizeof (net_ipv4
));
113 /* Let's connect to server */
114 if (connect (sock
, (sockaddr
*) &server_socket
,
115 sizeof (server_socket
)) == -1) {
116 DPRINT (DBG_DHCP
, "DHCP client -> Connection can't be estabilished");
117 ret
= DHCP_CONNECT_FAILED
;
121 net_proto_udp_anycast (sock
);
122 net_proto_udp_port (sock
, htons (68));
124 pos
= dhcp_request_header_prepare (request
, netif
,
125 DHCP_MESSAGE_TYPE_BOOTREQUEST
);
126 xid
= request
.bootp_header
->xid
;
128 buffer
[0] = DHCP_OPTION_VALUE_DHCPDISCOVER
;
129 pos
= dhcp_request_option_add (request
, DHCP_OPTION_MESSAGE_TYPE
,
133 memcpy (buffer
+ 1, netif
->dev
->dev_addr
, 6);
134 pos
= dhcp_request_option_add (request
, DHCP_OPTION_CLIENT_IDENTIFIER
,
137 char *hostname
= hostname_get ();
139 if (strlen (hostname
) <= 128) {
140 unsigned host_len
= strlen (hostname
);
141 pos
= dhcp_request_option_add (request
, DHCP_OPTION_HOSTNAME
,
142 buffer
, host_len
, pos
);
145 buffer
[0] = DHCP_OPTION_VALUE_SUBNET_MASK
;
146 buffer
[1] = DHCP_OPTION_VALUE_ROUTER
;
147 buffer
[2] = DHCP_OPTION_VALUE_DNS_SERVER
;
148 buffer
[3] = DHCP_OPTION_VALUE_DOMAIN_NAME
;
149 pos
= dhcp_request_option_add (request
, DHCP_OPTION_PARAMETER_REQUEST_LIST
,
154 DPRINT (DBG_DHCP
, "DHCP client -> sending request");
155 if (send (sock
, request
.buffer
, pos
, 0) < 0) {
156 DPRINT (DBG_DHCP
, "DHCP client -> Can't send request.");
157 ret
= DHCP_CANT_SEND_REQUEST
;
160 DPRINT (DBG_DHCP
, "DHCP client -> reuquest sended");
163 config_ip
= 0x00000000;
164 config_gw
= 0x00000000;
165 config_dns
= 0x00000000;
166 config_dhcp
= 0x00000000;
168 DPRINT (DBG_DHCP
, "DHCP client -> receiving response");
169 if ((recv_ret
= recv (sock
, request
.buffer
, DHCP_REQUEST_MAX_LEN
, 0)) < sizeof (dhcp_bootp_header_t
)) {
170 DPRINT (DBG_DHCP
, "DHCP client -> Can't receive response.");
171 ret
= DHCP_CANT_RECV_RESPONSE
;
174 DPRINT (DBG_DHCP
, "DHCP client -> response received");
176 if (request
.bootp_header
->mag_cookie
!= DHCP_MAGIC_COOKIE
) {
177 DPRINT (DBG_DHCP
, "DHCP client -> bad magic (finded 0x%X - needed 0x%X",
178 request
.bootp_header
->mag_cookie
, DHCP_MAGIC_COOKIE
);
179 ret
= DHCP_BAD_PACKET
;
183 pos
= sizeof (dhcp_bootp_header_t
);
185 config_ip
= request
.bootp_header
->yiaddr
;
187 if (request
.bootp_header
->xid
!= xid
) {
188 DPRINT (DBG_DHCP
, "DHCP client -> bad xid");
193 while (pos
< recv_ret
) {
194 unsigned int option_len
;
196 if (request
.buffer
[pos
] == DHCP_OPTION_PAD
) {
201 if (request
.buffer
[pos
] == DHCP_OPTION_END
)
204 if (pos
>= recv_ret
- 2) {
205 ret
= DHCP_BAD_PACKET
;
209 option_len
= request
.buffer
[pos
+ 1];
212 if (pos
+ option_len
>= recv_ret
) {
213 ret
= DHCP_BAD_PACKET
;
216 switch (request
.buffer
[pos
- 2]) {
217 case DHCP_OPTION_MESSAGE_TYPE
:
218 if (!option_len
== 1) {
219 ret
= DHCP_BAD_PACKET
;
222 switch (request
.buffer
[pos
]) {
223 case DHCP_OPTION_VALUE_DHCPOFFER
:
225 case DHCP_OPTION_VALUE_DHCPACK
:
228 case DHCP_OPTION_VALUE_DHCPNAK
:
229 ret
= DHCP_SRV_DIDNT_UNDERSTAND
;
233 DPRINT (DBG_DHCP
, "DHCP client -> bad DHCP message type");
237 case DHCP_OPTION_SUBNET_MASK
:
239 memcpy (&config_mask
, request
.buffer
+ pos
, sizeof (net_ipv4
));
241 case DHCP_OPTION_ROUTER
:
243 memcpy (&config_gw
, request
.buffer
+ pos
, sizeof (net_ipv4
));
245 case DHCP_OPTION_DNS_SERVER
:
247 memcpy (&config_dns
, request
.buffer
+ pos
, sizeof (net_ipv4
));
249 case DHCP_OPTION_DHCP_SERVER
:
251 memcpy (&config_dhcp
, request
.buffer
+ pos
, sizeof (net_ipv4
));
253 case DHCP_OPTION_LEASE_TIME
:
255 memcpy (&config_lease_time
, request
.buffer
+ pos
, sizeof (unsigned int));
264 DPRINT (DBG_DHCP
, "DHCP client -> response parsed");
269 pos
= dhcp_request_header_prepare (request
, netif
,
270 DHCP_MESSAGE_TYPE_BOOTREQUEST
);
272 buffer
[0] = DHCP_OPTION_VALUE_DHCPREQUEST
;
273 pos
= dhcp_request_option_add (request
, DHCP_OPTION_MESSAGE_TYPE
,
276 memcpy (buffer
, &config_ip
, 4);
277 pos
= dhcp_request_option_add (request
, DHCP_OPTION_REQUESTED_IP
,
280 memcpy (buffer
, &config_dhcp
, 4);
281 pos
= dhcp_request_option_add (request
, DHCP_OPTION_DHCP_SERVER
,
284 DPRINT (DBG_DHCP
, "DHCP client -> sending request");
285 if (send (sock
, request
.buffer
, pos
, 0) < 0) {
286 DPRINT (DBG_DHCP
, "DHCP client -> Can't send request.");
287 ret
= DHCP_CANT_SEND_REQUEST
;
290 DPRINT (DBG_DHCP
, "DHCP client -> request sended");
294 DPRINT (DBG_DHCP
, "DHCP client -> receiving response");
295 if ((recv_ret
= recv (sock
, request
.buffer
, DHCP_REQUEST_MAX_LEN
, 0)) < sizeof (dhcp_bootp_header_t
)) {
296 DPRINT (DBG_DHCP
, "DHCP client -> Can't receive response.");
297 ret
= DHCP_CANT_RECV_RESPONSE
;
300 DPRINT (DBG_DHCP
, "DHCP client -> response received");
302 if (request
.bootp_header
->mag_cookie
!= DHCP_MAGIC_COOKIE
) {
303 DPRINT (DBG_DHCP
, "DHCP client -> bad magic (finded 0x%X - needed 0x%X",
304 request
.bootp_header
->mag_cookie
, DHCP_MAGIC_COOKIE
);
305 ret
= DHCP_BAD_PACKET
;
309 if (request
.bootp_header
->xid
!= xid
) {
310 DPRINT (DBG_DHCP
, "DHCP client -> bad xid");
314 pos
= sizeof (dhcp_bootp_header_t
);
316 while (pos
< recv_ret
) {
317 unsigned int option_len
;
318 if (request
.buffer
[pos
] == DHCP_OPTION_PAD
) {
323 if (request
.buffer
[pos
] == DHCP_OPTION_END
)
326 if (pos
>= recv_ret
- 2) {
327 ret
= DHCP_BAD_PACKET
;
331 option_len
= request
.buffer
[pos
+ 1];
334 if (pos
+ option_len
>= recv_ret
) {
335 ret
= DHCP_BAD_PACKET
;
339 switch (request
.buffer
[pos
- 2]) {
340 case DHCP_OPTION_MESSAGE_TYPE
:
341 if (!option_len
== 1) {
342 ret
= DHCP_BAD_PACKET
;
345 switch (request
.buffer
[pos
]) {
346 case DHCP_OPTION_VALUE_DHCPOFFER
:
347 ret
= DHCP_BAD_PACKET
;
350 case DHCP_OPTION_VALUE_DHCPACK
:
352 case DHCP_OPTION_VALUE_DHCPNAK
:
353 ret
= DHCP_SRV_DIDNT_UNDERSTAND
;
357 DPRINT (DBG_DHCP
, "DHCP client -> bad DHCP message type");
361 case DHCP_OPTION_SUBNET_MASK
:
363 memcpy (&config_mask
, request
.buffer
+ pos
, sizeof (net_ipv4
));
365 case DHCP_OPTION_ROUTER
:
367 memcpy (&config_gw
, request
.buffer
+ pos
, sizeof (net_ipv4
));
369 case DHCP_OPTION_DNS_SERVER
:
371 memcpy (&config_dns
, request
.buffer
+ pos
, sizeof (net_ipv4
));
373 case DHCP_OPTION_LEASE_TIME
:
375 memcpy (&config_lease_time
, request
.buffer
+ pos
, sizeof (unsigned int));
385 DPRINT (DBG_DHCP
, "DHCP client -> configuring interface");
387 char *ip_str
= kmalloc (17); // 17 = IPv4 address in string maximum size + 1 zero
390 memset (ip_str
, 0, 17);
391 net_proto_ip_convert2 (config_ip
, ip_str
);
392 DPRINT (DBG_DHCP
, "DHCP client -> my IP: %s", ip_str
);
394 memset (ip_str
, 0, 17);
395 net_proto_ip_convert2 (config_gw
, ip_str
);
396 DPRINT (DBG_DHCP
, "DHCP client -> router IP: %s", ip_str
);
398 memset (ip_str
, 0, 17);
399 net_proto_ip_convert2 (config_dns
, ip_str
);
400 DPRINT (DBG_DHCP
, "DHCP client -> DNS server IP: %s", ip_str
);
402 DPRINT (DBG_DHCP
, "DHCP client -> IP lease time: %ud seconds", config_lease_time
);
405 dns_addr (config_dns
);
406 netif_ip_addr (netif
, config_ip
, IF_CFG_TYPE_DHCP
);
407 netif_gw_addr (netif
, config_gw
);
410 kfree (request
.buffer
);