FITkit
Fakulta informačních technologií

enc28j60_ip.c

Zobrazit dokumentaci tohoto souboru.
00001 /*******************************************************************************
00002    enc28j60_ip.c: Sitova vrstva modelu TCP/IP
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 
00045 #include "enc28j60_spi.h"
00046 #include "enc28j60_eth.h"
00047 #include "enc28j60_arp.h"
00048 #include "enc28j60_ip.h"
00049 #include "enc28j60_icmp.h"
00050 #include "enc28j60_tcp.h"
00051 #include "enc28j60_udp.h"
00052 
00053 // pro prevod 4xchar na 1 long, pro IP adresy, v "net order"
00054 #define CHAR_TO_LONG(x0,x1,x2,x3) ( ((unsigned long)x0<<24)|((unsigned long)x1<<16)|((unsigned int)x2<<8)|x3)
00055 
00056 
00057 extern unsigned char broadcast_mac[MAC_LEN];
00058 
00059 unsigned long local_ip = 0;
00060 unsigned long ip_netmask = 0;
00061 unsigned long default_gateway = 0;
00062 unsigned long dns_server = 0;
00063 unsigned int ip_seq_num = 1;
00064 
00065 
00069 void ip_recv(void){
00070         
00071         struct ip_h ip_header;
00072         
00073         if(rx_read(&ip_header,IP_HEADER_LEN) != IP_HEADER_LEN)
00074                 return;
00075         
00076         //kontrola verze IP a minimalni delky hlavicky
00077         if((ip_header.ipv != IPv4) | (ip_header.header_len < 4))
00078                 return;
00079                                 
00080         //kontrola fragmentacnich flagu
00081         if(ip_header.fragment & NTOHS(IP_FRAG_OFFSET|IP_FRAG_MORE))             //fragmentovany paket,zahodit
00082                 return; 
00083                 
00084         //kontrola IP adresy
00085         if(NTOHL(ip_header.dest_ip) != local_ip && (NTOHL(ip_header.dest_ip)|ip_netmask) != IP_BROADCAST )
00086                 return; 
00087                 
00088 
00089         //pokud je hlavicka delsi nez obvyklych 20B (volitelne polozky), zahodime je
00090         if( ( ((unsigned char)ip_header.header_len) <<2) > IP_HEADER_LEN){              //header_len *4
00091                 rx_skip ( ( ((unsigned char)ip_header.header_len) <<2) - IP_HEADER_LEN);
00092         }
00093         
00094         //odstraneni paddingu
00095         if(NTOHS(ip_header.length) < MIN_IP_LEN){
00096                 rx_cut_padding(MIN_IP_LEN - NTOHS(ip_header.length));
00097         
00098         }
00099 
00100 
00101         switch(ip_header.protocol){
00102                 case IP_PROTO_ICMP:
00103                         icmp_recv(&ip_header);
00104                         break;
00105                 case IP_PROTO_TCP:
00106                         tcp_recv(&ip_header);
00107                         break;
00108                 case IP_PROTO_UDP:
00109                         udp_recv(&ip_header);
00110                         break;
00111         }
00112         
00113 return;
00114 }       
00115 
00119 char ip_send(unsigned long dest_addr,unsigned char protocol){
00120         
00121         struct ip_h ip_header;
00122         
00123         tx_seek(IP_HEADER);                                                             //jiz zde kvuli volani tx_data_len() nize
00124         
00125         ip_header.ipv = IPv4;
00126         ip_header.header_len = IP_HEADER_LEN >> 2;              // deleno ctyrmi, udava se totiz v DWORD
00127         ip_header.tos = 0;
00128         ip_header.length = HTONS(tx_data_len());
00129         ip_header.identification = HTONS(ip_seq_num);
00130         ip_seq_num++;
00131         
00132         ip_header.fragment = 0;
00133         ip_header.ttl = DEFAULT_TTL;
00134         ip_header.protocol = protocol;
00135         ip_header.checksum = 0;
00136         ip_header.src_ip = HTONL(local_ip);
00137         ip_header.dest_ip = HTONL(dest_addr);
00138         
00139                 //pri pocitani checksumu z hlavicky, ktera je big endian, jiz nemusime checksum prevadet pomoci HTONS
00140         ip_header.checksum = count_checksum(&ip_header,IP_HEADER_LEN);
00141 
00142         
00143         tx_write(&ip_header,IP_HEADER_LEN);
00144         
00145         
00146         //*****************************
00147         //cil nelezi ve stejne podsiti
00148         //*****************************
00149         if(default_gateway != 0){
00150                 if((local_ip & ip_netmask) != (dest_addr & ip_netmask)){
00151                         dest_addr = default_gateway;
00152                 }
00153         }
00154         
00155         //********
00156         //ARP
00157         //*********
00158         char * dest_mac;
00159         
00160         if(dest_addr == IP_BROADCAST){                  //IP broadcast se posila na broadcastovou mac
00161                 dest_mac = broadcast_mac;
00162         }
00163         else{
00164                 dest_mac = arp_table_find(dest_addr);
00165         }
00166         
00167         if(dest_mac == NULL){                                           //neexistuje arp zaznam
00168                 
00169                 //ulozeni ukazatelu do bufferu behem vyrizovani ARP dotazu
00170                 unsigned char last_act = tx_act();
00171                 
00172                 tx_save(last_act);
00173                 
00174                 //odeslani ARP dotazu
00175                 arp_send(dest_addr);
00176                 
00177                 unsigned int timer = ARP_TIMEOUT;               //timeout
00178                 
00179                 //cekani na ARP odpoved
00180                 while((arp_table_find(dest_addr) == NULL) & (timer-- > 0) ){ //az dojde odpoved, zapise se do arp tabulky
00181                         ENC28J60_idle();                                                //obsluha prichozich paketu
00182                 };
00183                 
00184                 dest_mac = arp_table_find(dest_addr);
00185                 
00186                 if( dest_mac == NULL){                                          //odpoved na arp nedosla do timeoutu
00187                         if(last_act == TX1)
00188                                 tx_unlock(TX1);                                                 //vypnuti ochrany proti prepsani tx bufferu
00189                         else if(last_act == TX2)
00190                                 tx_unlock(TX2); 
00191 
00192                                 
00193                         return -2;
00194                 }
00195                 else{
00196                         tx_load(last_act);
00197                         return eth_send(dest_mac,ETH_PROTO_IP);         //odeslani paketu na ziskanou mac adresu
00198                 }
00199                 
00200         }
00201         
00202 return eth_send(dest_mac,ETH_PROTO_IP);
00203 }
00204 
00205 
00209 unsigned int count_checksum(void* pointer,int count){   //vypocet CRC souctu,podle RFC 1071
00210 
00211   unsigned long sum = 0;
00212   unsigned int* ptr = (unsigned int*)pointer;
00213 
00214         while( count > 1 ){
00215                         sum += *(ptr++);
00216                         count -=2;
00217                 }
00218                 
00219                 if(count == 1)
00220                         sum += *((unsigned char*) ptr);
00221 
00222                 while(sum >> 16){
00223                 sum = (sum & 0xFFFF) + (sum >> 16);
00224                 }
00225      
00226 return (unsigned int) ~sum;
00227 }
00228 
00229 
00230 
00234 inline void set_ip(unsigned char a0,unsigned char a1,unsigned char a2, unsigned char a3){
00235         local_ip = CHAR_TO_LONG(a0,a1,a2,a3);
00236 }
00237 
00241 inline void set_ip_l(unsigned long ip){
00242         local_ip = ip;
00243 }
00247 inline unsigned long get_ip(){
00248         return local_ip;
00249 }
00250 
00254 inline void set_netmask(unsigned char m0,unsigned char m1,unsigned char m2, unsigned char m3){
00255         ip_netmask = CHAR_TO_LONG(m0,m1,m2,m3);
00256 }
00260 inline void set_netmask_l(unsigned long netmask){
00261         ip_netmask = netmask;
00262 }
00266 inline unsigned long get_netmask(){
00267         return ip_netmask;
00268 }
00269 
00273 inline void set_gateway(unsigned char g0,unsigned char g1,unsigned char g2, unsigned char g3){
00274         default_gateway = CHAR_TO_LONG(g0,g1,g2,g3);
00275 }
00279 inline void set_gateway_l(unsigned long gateway){
00280         default_gateway = gateway;
00281 }
00285 inline unsigned long get_gateway(){
00286         return default_gateway;
00287 }
00288 
00292 inline void set_dns_server(unsigned char d0,unsigned char d1,unsigned char d2, unsigned char d3){
00293         dns_server = CHAR_TO_LONG(d0,d1,d2,d3);
00294 }
00298 inline void set_dns_server_l(unsigned long dns){
00299         dns_server = dns;
00300 }
00304 inline unsigned long get_dns_server(){
00305         return dns_server;
00306 }
00307