Aktuální adresář: FITkit /
trunk /
mcu /
libs /
enc28j60 /
enc28j60_dhcp.c
1 /*******************************************************************************
2 enc28j60_dhcp.c: Implementace protokolu DHCP.
3 Copyright (C) 2010 Brno University of Technology,
4 Faculty of Information Technology
5 Author(s): Martin Musil <xmusil34 AT fit.vutbr.cz>
6
7 LICENSE TERMS
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in
16 the documentation and/or other materials provided with the
17 distribution.
18 3. All advertising materials mentioning features or use of this software
19 or firmware must display the following acknowledgement:
20
21 This product includes software developed by the University of
22 Technology, Faculty of Information Technology, Brno and its
23 contributors.
24
25 4. Neither the name of the Company nor the names of its contributors
26 may be used to endorse or promote products derived from this
27 software without specific prior written permission.
28
29 This software or firmware is provided ``as is'', and any express or implied
30 warranties, including, but not limited to, the implied warranties of
31 merchantability and fitness for a particular purpose are disclaimed.
32 In no event shall the company or contributors be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability, whether
37 in contract, strict liability, or tort (including negligence or
38 otherwise) arising in any way out of the use of this software, even
39 if advised of the possibility of such damage.
40
41 $Id$
42
43 *******************************************************************************/
44 #include "enc28j60_dhcp.h"
45 #include "enc28j60_udp.h"
46 #include "enc28j60_ip.h"
47 #include "enc28j60_arp.h"
48 #include "enc28j60_spi.h"
49
50 #include "enc28j60_string.h"
51
52 extern unsigned char local_mac[MAC_LEN];
53 unsigned char dhcp_state = DHCP_DISCOVER;
54 unsigned long magic_cookie = 0x63538263;
55
56 unsigned char dhcp_message_type;
57 unsigned long dhcp_server_id = 0;
58 unsigned long dhcp_netmask = 0;
59 unsigned long dhcp_router = 0;
60 unsigned long dhcp_dns_server = 0;
61 unsigned long dhcp_transaction_id = 0x12345678;
62 unsigned long dhcp_requested_ip = 0;
63 unsigned char dhcp_timeout = DHCP_TIMEOUT;
64
65
66 char dhcp_send_discover();
67
68 char dhcp_send_request();
69
70 // UDP handler - prijem DHCP zprav
71 UDP_APP_HANDLER(dhcp_fsm){
72 //term_send_str_crlf(" DHCP zprava");
73 struct bootp_h bootp_header;
74
75 if(rx_left() < BOOTP_HEADER_LEN_TOTAL + MAGIC_LEN) //paket musi byt vetsi nez bootp hlavicka + magic cookie
76 return;
77
78 rx_read(&bootp_header, BOOTP_HEADER_LEN);
79
80 if(bootp_header.opcode != BOOTP_REPLY){ //pouze BOOTP odpovedi
81 return;}
82
83 if(bootp_header.hw_type != BOOTP_HW_ETH){ //pouze ethernet protokol
84 return;}
85
86
87 return;}
88
89 if(bootp_header.transaction_id != dhcp_transaction_id){ //kontrola ID transkace (pouzivam cast MAC adresy)
90 return;}
91
92 rx_skip(BOOTP_HEADER_LEN_TOTAL - BOOTP_HEADER_LEN); //prekoceni dalsich polozek hlavicky (server name, filename)
93
94 //magic packet
95 unsigned long dhcp_magic;
96 rx_read(&dhcp_magic,MAGIC_LEN);
97
98 if(dhcp_magic != MAGIC_COOKIE) //kontrola pritomnosti magic_cookie
99 return;
100
101 dhcp_requested_ip = bootp_header.your_ip; //nabizena IP adresa
102 unsigned int option;
103
104 //cteni DHCP nastaveni
105 while((rx_left() >0) & ((option=rx_getc()) != DHCP_END)){ //precteni typu parametru
106
107 if(option == DHCP_PAD) //mezera
108 continue;
109
110 int len = rx_getc(); //delka parametru
111
112 switch(option){
113 case DHCP_MESSAGE_TYPE: //typ zpravy
114 dhcp_message_type = rx_getc();
115 break;
116 case DHCP_ROUTER: //IP routeru
117 rx_read(&dhcp_router,IP_LEN);
118 break;
119 case DHCP_DNS_SERVER: //IP DNS serveru
120 rx_read(&dhcp_dns_server,IP_LEN);
121 break;
122 case DHCP_SERVER_ID: //IP DHCP serveru
123 rx_read(&dhcp_server_id,IP_LEN);
124 break;
125 case DHCP_SUBNET_MASK: //maska podsite
126 rx_read(&dhcp_netmask,IP_LEN);
127 break;
128
129 default:
130 rx_skip(len);
131 }
132 }
133 switch(dhcp_state){
134 case DHCP_DISCOVER:
135
136 switch(dhcp_message_type){ //prislusna akce na prichozi zpravu
137 case DHCP_OFFER: //nabidka IP
138 dhcp_state = DHCP_REQUEST;
139 dhcp_timeout = DHCP_TIMEOUT;
140 dhcp_send_request();
141 break;
142
143 default:
144 dhcp_reset();
145 }
146
147 case DHCP_REQUEST:
148
149 switch(dhcp_message_type){ //prislusna akce na prichozi zpravu
150
151 //potvrzeni, ze se muze nabidnuta IP adresa pouzivat
152 case DHCP_ACK:
153
154 //nastaveni IP adresy,masky,brany,DNS
155 set_ip_l(HTONL(dhcp_requested_ip));
156 set_netmask_l(HTONL(dhcp_netmask));
157 set_gateway_l(HTONL(dhcp_router));
158 set_dns_server_l(HTONL(dhcp_dns_server));
159 dhcp_state = DHCP_ACK;
160
161 //zavreni socketu s DHCP
162 udp_unbind(DHCP_CLIENT_PORT);
163 break;
164
165 case DHCP_OFFER:
166 break;
167 //odmitnuti serveru
168 case DHCP_DECLINE:
169 case DHCP_NACK:
170 dhcp_reset();
171 break;
172 }
173 }
174 return;
175 }
176
177
178 /**
179 \brief Inicializace DHCP protokolu.
180 **/
181 char dhcp_init(){
182 set_ip(0,0,0,0); //nulovani IP adres
183 set_netmask(255,255,255,255);
184 set_gateway(0,0,0,0);
185 dhcp_state = DHCP_DISCOVER;
186 dhcp_timeout = DHCP_TIMEOUT;
187 enc_memcpy(&dhcp_transaction_id, &local_mac,MAC_LEN -2); //ID transkace (pouziva se cast MAC adresy)
188
189 //zaregistrovani portu 68 pro prijem DHCP zprav
190 return udp_bind(DHCP_CLIENT_PORT,dhcp_fsm);
191 }
192
193 /**
194 \brief Restart DHCP klienta.
195 **/
196 char dhcp_reset(){
197 set_ip(0,0,0,0); //nulovani IP adres
198 set_netmask(255,255,255,255);
199 set_gateway(0,0,0,0);
200 dhcp_state = DHCP_DISCOVER;
201 dhcp_timeout = DHCP_TIMEOUT;
202 dhcp_transaction_id++;
203
204 //zaregistrovani portu 68 pro prijem DHCP zprav
205 return udp_bind(DHCP_CLIENT_PORT,dhcp_fsm);
206 }
207
208 /**
209
210
211 **/
212 void dhcp_timer(){
213
214 if(dhcp_timeout == 0)
215 dhcp_reset();
216
217 switch(dhcp_state){
218
219 case DHCP_DISCOVER:
220 dhcp_send_discover();
221 dhcp_timeout--;
222 break;
223
224 case DHCP_REQUEST:
225 dhcp_send_request();
226 dhcp_timeout--;
227 break;
228
229 case DHCP_ACK:
230
231 if(link_change()){ //stav linky se zmenil
232
233 if(!link_up()){ //kontrola, zda je linka zapnuta
234
235 //kabel odpojen, reset DHCP nastaveni
236 dhcp_reset();
237 arp_table_clear();
238 return;
239 }
240 }
241 break;
242 }
243
244 return;
245 }
246
247 /**
248
249 **/
250 char dhcp_ready(){
251
252 if(dhcp_state == DHCP_ACK){
253 return 1;
254 }
255
256 return 0;
257 }
258
259
260
261 char dhcp_send_discover(){
262
263 struct bootp_h bootp_header;
264 enc_memset(&bootp_header,0,BOOTP_HEADER_LEN);
265
266 //vyplneni hlavicky
267 bootp_header.opcode = BOOTP_REQUEST;
268 bootp_header.hw_type = BOOTP_HW_ETH;
269 bootp_header.hw_address_length = MAC_LEN;
270 bootp_header.transaction_id = dhcp_transaction_id;
271 enc_memcpy(&bootp_header.client_hw_address, &local_mac, MAC_LEN);
272
273 //inicializace bufferu
274 if(tx_init(UDP_PROTO) < 0)
275 return -1;
276
277 //zapsani hlavicky
278 tx_write(&bootp_header,BOOTP_HEADER_LEN);
279 //vyplneni mista pro host name a boot filename
280 tx_fill(0,BOOTP_HEADER_LEN_TOTAL - BOOTP_HEADER_LEN);
281 //magic cookie
282 tx_write(&magic_cookie,MAGIC_LEN);
283
284 //DHCP request (zadost)
285 tx_putc(DHCP_MESSAGE_TYPE);
286 tx_putc(1);
287 tx_putc(DHCP_DISCOVER);
288
289 tx_putc(12); //typ:hostname
290 tx_putc(6); //delka
291 tx_write("FITKit",6); //hodnota
292
293
294 tx_putc(55); //typ:parameter request list
295 tx_putc(3); //delka
296 tx_putc(1); //maska
297 tx_putc(3); //router
298 tx_putc(6); //DNS
299
300 tx_putc(DHCP_END); //ukonceni DHCP zadosti
301
302 tx_close();
303
304 //odeslani DHCP zadosti
305 udp_send(DHCP_SERVER_PORT,DHCP_CLIENT_PORT,IP_BROADCAST);
306
307 dhcp_state = DHCP_DISCOVER;
308
309 return 0;
310 }
311
312 char dhcp_send_request(){
313
314 //inicializace tx bufferu
315 if(tx_init(UDP_PROTO) < 0)
316 return -1;
317
318 //vytvoreni BOOTP hlavicky
319 struct bootp_h bootp_header;
320 enc_memset(&bootp_header,0,BOOTP_HEADER_LEN);
321
322 bootp_header.opcode = BOOTP_REQUEST;
323 bootp_header.hw_type = BOOTP_HW_ETH;
324 bootp_header.hw_address_length = MAC_LEN;
325 bootp_header.transaction_id = dhcp_transaction_id;
326 enc_memcpy(&bootp_header.client_hw_address, &local_mac, MAC_LEN);
327
328 //zapis do tx bufferu
329 tx_write(&bootp_header, BOOTP_HEADER_LEN);
330 tx_fill(0,BOOTP_HEADER_LEN_TOTAL - BOOTP_HEADER_LEN);
331
332 //DHCP magic_cookie
333 tx_write(&magic_cookie,MAGIC_LEN);
334
335 //zapsani DHCP parametru
336 tx_putc(DHCP_MESSAGE_TYPE); //typ zpravy
337 tx_putc(1);
338 tx_putc(DHCP_REQUEST); //zadost
339
340 tx_putc(DHCP_REQUESTED_IP); //zadost o nabizenou IP
341 tx_putc(4);
342 tx_write(&dhcp_requested_ip, IP_LEN);
343
344 tx_putc(DHCP_SERVER_ID); // ID DHCP serveru, ktery ucinil nabidku
345 tx_putc(4);
346 tx_write(&dhcp_server_id, IP_LEN);
347
348
349 tx_putc(12); //typ:hostname
350 tx_putc(6); //delka
351 tx_write("FITKit",6); //hodnota
352
353
354 tx_putc(55); //typ:parameter request list
355 tx_putc(3); //delka
356 tx_putc(1); //maska
357 tx_putc(3); //router
358 tx_putc(6); //DNS
359
360
361 tx_putc(DHCP_END); //ukonceni DHCP zadosti
362 tx_close();
363
364 //odeslani
365 udp_send(DHCP_SERVER_PORT,DHCP_CLIENT_PORT,IP_BROADCAST);
366
367 dhcp_state = DHCP_REQUEST;
368
369 return 0;
370 }
371