FITkit
Fakulta informačních technologií

enc28j60_dhcp.c

Zobrazit dokumentaci tohoto souboru.
00001 /*******************************************************************************
00002    enc28j60_dhcp.c: Implementace protokolu DHCP.
00003    Copyright (C) 2010 Brno University of Technology,
00004                       Faculty of Information Technology
00005    Author(s): Martin Musil <xmusil34 AT fit.vutbr.cz>
00006 
00007    LICENSE TERMS
00008 
00009    Redistribution and use in source and binary forms, with or without
00010    modification, are permitted provided that the following conditions
00011    are met:
00012    1. Redistributions of source code must retain the above copyright
00013       notice, this list of conditions and the following disclaimer.
00014    2. Redistributions in binary form must reproduce the above copyright
00015       notice, this list of conditions and the following disclaimer in
00016       the documentation and/or other materials provided with the
00017       distribution.
00018    3. All advertising materials mentioning features or use of this software
00019       or firmware must display the following acknowledgement:
00020 
00021         This product includes software developed by the University of
00022         Technology, Faculty of Information Technology, Brno and its
00023         contributors.
00024 
00025    4. Neither the name of the Company nor the names of its contributors
00026       may be used to endorse or promote products derived from this
00027       software without specific prior written permission.
00028 
00029    This software or firmware is provided ``as is'', and any express or implied
00030    warranties, including, but not limited to, the implied warranties of
00031    merchantability and fitness for a particular purpose are disclaimed.
00032    In no event shall the company or contributors be liable for any
00033    direct, indirect, incidental, special, exemplary, or consequential
00034    damages (including, but not limited to, procurement of substitute
00035    goods or services; loss of use, data, or profits; or business
00036    interruption) however caused and on any theory of liability, whether
00037    in contract, strict liability, or tort (including negligence or
00038    otherwise) arising in any way out of the use of this software, even
00039    if advised of the possibility of such damage.
00040 
00041    $Id$
00042 
00043 *******************************************************************************/ 
00044 #include "enc28j60_dhcp.h"
00045 #include "enc28j60_udp.h"
00046 #include "enc28j60_ip.h"
00047 #include "enc28j60_arp.h"
00048 #include "enc28j60_spi.h"
00049 
00050 #include "enc28j60_string.h"
00051 
00052 extern unsigned char local_mac[MAC_LEN];
00053 unsigned char dhcp_state = DHCP_DISCOVER;
00054 unsigned long magic_cookie = 0x63538263;
00055 
00056 unsigned char dhcp_message_type;
00057 unsigned long dhcp_server_id = 0;
00058 unsigned long dhcp_netmask = 0;
00059 unsigned long dhcp_router = 0;
00060 unsigned long dhcp_dns_server = 0;
00061 unsigned long dhcp_transaction_id = 0x12345678;
00062 unsigned long dhcp_requested_ip = 0;
00063 unsigned char dhcp_timeout = DHCP_TIMEOUT;
00064         
00065 //Odeslání discover zprávy
00066 char dhcp_send_discover();
00067 //odeslání request zprávy
00068 char dhcp_send_request();
00069 
00070 // UDP handler - prijem DHCP zprav
00071 UDP_APP_HANDLER(dhcp_fsm){
00072         //term_send_str_crlf(" DHCP zprava");
00073         struct bootp_h bootp_header;
00074         
00075         if(rx_left() < BOOTP_HEADER_LEN_TOTAL + MAGIC_LEN)      //paket musi byt vetsi nez bootp hlavicka + magic cookie
00076                 return;
00077         
00078         rx_read(&bootp_header, BOOTP_HEADER_LEN);
00079 
00080         if(bootp_header.opcode != BOOTP_REPLY){                         //pouze BOOTP odpovedi
00081                 return;}
00082                 
00083         if(bootp_header.hw_type != BOOTP_HW_ETH){                       //pouze ethernet protokol
00084                 return;}
00085 
00086         if(bootp_header.hw_address_length != MAC_LEN){          //6-bajtová MAC
00087                 return;}
00088         
00089         if(bootp_header.transaction_id != dhcp_transaction_id){         //kontrola ID transkace (pouzivam cast MAC adresy)
00090                 return;}
00091                 
00092         rx_skip(BOOTP_HEADER_LEN_TOTAL - BOOTP_HEADER_LEN);                                             //prekoceni dalsich polozek hlavicky (server name, filename)
00093         
00094                 //magic packet
00095         unsigned long dhcp_magic;
00096         rx_read(&dhcp_magic,MAGIC_LEN);
00097                 
00098         if(dhcp_magic != MAGIC_COOKIE)                                                                  //kontrola pritomnosti magic_cookie
00099                 return;
00100                 
00101         dhcp_requested_ip = bootp_header.your_ip;                                                       //nabizena IP adresa
00102         unsigned int option;
00103 
00104                 //cteni DHCP nastaveni
00105         while((rx_left() >0) & ((option=rx_getc()) != DHCP_END)){               //precteni typu parametru
00106                 
00107                 if(option == DHCP_PAD)                                                  //mezera
00108                         continue;
00109 
00110                 int len = rx_getc();                                    //delka parametru
00111 
00112                 switch(option){
00113                         case DHCP_MESSAGE_TYPE:                         //typ zpravy
00114                                 dhcp_message_type = rx_getc();  
00115                                 break;
00116                         case DHCP_ROUTER:                                       //IP routeru
00117                                 rx_read(&dhcp_router,IP_LEN);
00118                                 break;
00119                         case DHCP_DNS_SERVER:                           //IP DNS serveru
00120                                 rx_read(&dhcp_dns_server,IP_LEN);
00121                                 break;
00122                         case DHCP_SERVER_ID:                            //IP DHCP serveru
00123                                 rx_read(&dhcp_server_id,IP_LEN);        
00124                                 break;
00125                         case DHCP_SUBNET_MASK:                          //maska podsite
00126                                 rx_read(&dhcp_netmask,IP_LEN);
00127                                 break;
00128                 
00129                         default:
00130                                 rx_skip(len);
00131                 }       
00132         }
00133         switch(dhcp_state){
00134                 case DHCP_DISCOVER:
00135                         
00136                         switch(dhcp_message_type){              //prislusna akce na prichozi zpravu
00137                                 case DHCP_OFFER:                //nabidka IP
00138                                                 dhcp_state = DHCP_REQUEST;
00139                                                 dhcp_timeout = DHCP_TIMEOUT;
00140                                                 dhcp_send_request();
00141                                         break;
00142                                         
00143                                 default:
00144                                                 dhcp_reset();
00145                         }
00146                         
00147                 case DHCP_REQUEST:
00148                         
00149                         switch(dhcp_message_type){                      //prislusna akce na prichozi zpravu
00150                                         
00151                                         //potvrzeni, ze se muze nabidnuta IP adresa pouzivat
00152                                 case DHCP_ACK:
00153                                         
00154                                         //nastaveni IP adresy,masky,brany,DNS
00155                                         set_ip_l(HTONL(dhcp_requested_ip));
00156                                         set_netmask_l(HTONL(dhcp_netmask));
00157                                         set_gateway_l(HTONL(dhcp_router));
00158                                         set_dns_server_l(HTONL(dhcp_dns_server));
00159                                         dhcp_state = DHCP_ACK;
00160                 
00161                                         //zavreni socketu s DHCP
00162                                         udp_unbind(DHCP_CLIENT_PORT);
00163                                         break;  
00164                                         
00165                                 case DHCP_OFFER:
00166                                         break;  
00167                                         //odmitnuti serveru
00168                                 case DHCP_DECLINE:      
00169                                 case DHCP_NACK:
00170                                         dhcp_reset();
00171                                         break;
00172                         }               
00173         }
00174 return;
00175 }
00176 
00177 
00181 char dhcp_init(){
00182         set_ip(0,0,0,0);                                //nulovani IP adres
00183         set_netmask(255,255,255,255);
00184         set_gateway(0,0,0,0);
00185         dhcp_state = DHCP_DISCOVER;
00186         dhcp_timeout = DHCP_TIMEOUT;
00187         enc_memcpy(&dhcp_transaction_id, &local_mac,MAC_LEN -2);        //ID transkace (pouziva se cast MAC adresy)
00188         
00189         //zaregistrovani portu 68 pro prijem DHCP zprav
00190 return udp_bind(DHCP_CLIENT_PORT,dhcp_fsm);
00191 }
00192 
00196 char dhcp_reset(){
00197         set_ip(0,0,0,0);                                //nulovani IP adres
00198         set_netmask(255,255,255,255);
00199         set_gateway(0,0,0,0);
00200         dhcp_state = DHCP_DISCOVER;
00201         dhcp_timeout = DHCP_TIMEOUT;
00202         dhcp_transaction_id++;
00203         
00204         //zaregistrovani portu 68 pro prijem DHCP zprav
00205 return udp_bind(DHCP_CLIENT_PORT,dhcp_fsm);     
00206 }
00207 
00212 void dhcp_timer(){
00213         
00214         if(dhcp_timeout == 0)
00215                 dhcp_reset();
00216         
00217         switch(dhcp_state){
00218                 
00219                 case DHCP_DISCOVER:
00220                         dhcp_send_discover();
00221                         dhcp_timeout--;
00222                         break;
00223                 
00224                 case DHCP_REQUEST:
00225                         dhcp_send_request();
00226                         dhcp_timeout--; 
00227                         break;
00228                 
00229                 case DHCP_ACK:
00230                         
00231                         if(link_change()){              //stav linky se zmenil
00232                         
00233                                 if(!link_up()){         //kontrola, zda je linka zapnuta
00234                                                         
00235                                         //kabel odpojen, reset DHCP nastaveni
00236                                         dhcp_reset();
00237                                         arp_table_clear();
00238                                         return; 
00239                                 }
00240                         }
00241                         break;
00242         }
00243         
00244 return;
00245 }
00246 
00250 char dhcp_ready(){
00251         
00252         if(dhcp_state == DHCP_ACK){
00253                 return 1;
00254         }
00255         
00256 return 0;       
00257 }
00258 
00259 
00260 //Odeslání discover zprávy
00261 char dhcp_send_discover(){
00262 
00263         struct bootp_h bootp_header;
00264         enc_memset(&bootp_header,0,BOOTP_HEADER_LEN);
00265         
00266                 //vyplneni hlavicky
00267         bootp_header.opcode = BOOTP_REQUEST;
00268         bootp_header.hw_type = BOOTP_HW_ETH;
00269         bootp_header.hw_address_length = MAC_LEN;
00270         bootp_header.transaction_id = dhcp_transaction_id;
00271         enc_memcpy(&bootp_header.client_hw_address, &local_mac, MAC_LEN);
00272         
00273                 //inicializace bufferu
00274         if(tx_init(UDP_PROTO) < 0)
00275                 return -1;
00276         
00277                 //zapsani hlavicky
00278         tx_write(&bootp_header,BOOTP_HEADER_LEN);
00279                 //vyplneni mista pro host name a boot filename
00280         tx_fill(0,BOOTP_HEADER_LEN_TOTAL - BOOTP_HEADER_LEN);
00281                 //magic cookie
00282         tx_write(&magic_cookie,MAGIC_LEN);
00283         
00284                 //DHCP request (zadost)
00285         tx_putc(DHCP_MESSAGE_TYPE);
00286         tx_putc(1);
00287         tx_putc(DHCP_DISCOVER);
00288 
00289         tx_putc(12);                    //typ:hostname
00290         tx_putc(6);                             //delka
00291         tx_write("FITKit",6);   //hodnota
00292 
00293 
00294         tx_putc(55);                    //typ:parameter request list
00295         tx_putc(3);                             //delka
00296         tx_putc(1);                             //maska
00297         tx_putc(3);                             //router
00298         tx_putc(6);                             //DNS
00299         
00300         tx_putc(DHCP_END);              //ukonceni DHCP zadosti
00301         
00302         tx_close();
00303         
00304                 //odeslani DHCP zadosti
00305         udp_send(DHCP_SERVER_PORT,DHCP_CLIENT_PORT,IP_BROADCAST);
00306 
00307         dhcp_state = DHCP_DISCOVER;
00308 
00309 return 0; 
00310 }
00311 
00312 char dhcp_send_request(){
00313         
00314                 //inicializace tx bufferu
00315         if(tx_init(UDP_PROTO) < 0)
00316                 return -1;
00317         
00318                 //vytvoreni BOOTP hlavicky
00319         struct bootp_h bootp_header;
00320         enc_memset(&bootp_header,0,BOOTP_HEADER_LEN);
00321         
00322         bootp_header.opcode = BOOTP_REQUEST;
00323         bootp_header.hw_type = BOOTP_HW_ETH;
00324         bootp_header.hw_address_length = MAC_LEN;
00325         bootp_header.transaction_id = dhcp_transaction_id;
00326         enc_memcpy(&bootp_header.client_hw_address, &local_mac, MAC_LEN);
00327         
00328                 //zapis do tx bufferu
00329         tx_write(&bootp_header, BOOTP_HEADER_LEN);
00330         tx_fill(0,BOOTP_HEADER_LEN_TOTAL - BOOTP_HEADER_LEN);
00331                 
00332                 //DHCP magic_cookie
00333         tx_write(&magic_cookie,MAGIC_LEN);
00334         
00335                 //zapsani DHCP parametru
00336         tx_putc(DHCP_MESSAGE_TYPE);             //typ zpravy
00337         tx_putc(1);
00338         tx_putc(DHCP_REQUEST);                  //zadost
00339         
00340         tx_putc(DHCP_REQUESTED_IP);             //zadost o nabizenou IP
00341         tx_putc(4);
00342         tx_write(&dhcp_requested_ip, IP_LEN);
00343         
00344         tx_putc(DHCP_SERVER_ID);                // ID DHCP serveru, ktery ucinil nabidku
00345         tx_putc(4);
00346         tx_write(&dhcp_server_id, IP_LEN);
00347         
00348         
00349         tx_putc(12);                    //typ:hostname
00350         tx_putc(6);                             //delka
00351         tx_write("FITKit",6);   //hodnota
00352 
00353 
00354         tx_putc(55);                    //typ:parameter request list
00355         tx_putc(3);                             //delka
00356         tx_putc(1);                             //maska
00357         tx_putc(3);                             //router
00358         tx_putc(6);                             //DNS
00359                         
00360         
00361         tx_putc(DHCP_END);              //ukonceni DHCP zadosti
00362         tx_close();
00363         
00364                 //odeslani
00365         udp_send(DHCP_SERVER_PORT,DHCP_CLIENT_PORT,IP_BROADCAST);
00366                 
00367         dhcp_state = DHCP_REQUEST;
00368 
00369 return 0;
00370 }