arp.c

Go to the documentation of this file.
00001 /*##############################################################################
00002 
00003 nIP - nano IP stack
00004 
00005 File        : arp.c
00006 
00007 Description : Functions to serve ethernet interfaces
00008 
00009 Copyright notice:
00010 
00011 Copyright (C) 2005 -
00012 Andreas Dittrich, dittrich@informatik.hu-berlin.de
00013 Jon Kowal, kowal@informatik.hu-berlin.de
00014 
00015 This program is free software; you can redistribute it and/or
00016 modify it under the terms of the GNU General Public License
00017 as published by the Free Software Foundation; either version 2
00018 of the License, or (at your option) any later version.
00019 
00020 This program is distributed in the hope that it will be useful,
00021 but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00023 GNU General Public License for more details.
00024 
00025 You should have received a copy of the GNU General Public License
00026 along with this program; if not, write to the Free Software
00027 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00028 
00029 ##############################################################################*/
00030 
00031 #include "dispatcher.h"
00032 #include "inet.h"
00033 #include "net/arp.h"
00034 #include "net/net_if.h"
00035 #include "net/ip.h"
00036 #include "net/numbers.h"
00037 #include "net/autoip.h"
00038 #include "os_core.h"
00039 
00040 
00041 #if (NIP_ARP_ENABLE == 1)
00042 
00043 extern nip_net_if_t nip_net_if_list[];
00044 extern nip_disp_state_t nip_disp;
00045 
00046 /** Array with ARP Cache entries */
00047 static struct ARP_CACHE arp_cache[ NIP_ARP_CACHE_SIZE ];
00048 
00049 // uint8_t uint32_gt( uint32_t *i1, uint32_t *i2 )
00050 // {
00051 //      return ( *i1 > *i2 );
00052 // }
00053 
00054 #define uint32_gt( i1, i2 ) *i1>*i2
00055 
00056 /** Find ARP cache entry by Protocol address.
00057  *
00058  * If pr_addr is NULL or was not found in cache, a pointer to an unused or
00059  * expired cache entry will be returned in `'entry''. If no unused or expired
00060  * cache entry is available a pointer to the entry with the oldest timestamp
00061  * will be returned.
00062  *
00063  * @return NIP_ERROR if pr_addr is not NULL and no unexpired entry with that
00064  * address has been found or if pr_addr is NULL and no unused or expired entry
00065  * has been found. NIP_SUCCESS, else. In any case `'entry'' will point to a
00066  * cache entry to be used to store new address information.
00067  */
00068 static nip_success_t nip_arp_cache_lookup( uint8_t *pr_addr, struct ARP_CACHE **entry )
00069 {
00070         arp_cache_id_t   cnt;
00071         nip_success_t    res;
00072         struct ARP_CACHE *e;
00073 
00074         cnt = 0;
00075         *entry = &arp_cache[ cnt ];
00076         do
00077         {
00078                 e = &arp_cache[ cnt ];
00079 
00080                 // remember entry with oldest timestamp
00081                 if ( uint32_gt( &(*entry)->timestamp, &e->timestamp ) ) *entry = e;
00082 
00083                 if ( uint32_gt( &e->timestamp, &nip_tickcount() ) )
00084                 {
00085                         res = NIP_SUCCESS;
00086                 }
00087                 else if ( pr_addr == NULL )
00088                 {
00089                         *entry = e;
00090                         return NIP_SUCCESS;
00091                 }
00092                 else
00093                         res = NIP_ERROR;
00094 
00095                 // Found entry with matching protocol address. Return ERROR or SUCCESS
00096                 // depending on timestamp.
00097                 if ( pr_addr != NULL && nip_memcmp( pr_addr, e->pr_addr, NIP_ARP_PR_SIZE ) == 0 )
00098                 {
00099                         *entry = e;
00100                         return res;
00101                 }
00102 
00103         } while ( ++cnt < NIP_ARP_CACHE_SIZE );
00104 
00105         // if the searched entry was not found, return ERROR
00106         return NIP_ERROR;
00107 }
00108 
00109 /** Fill default values for ARP packet and transmit.
00110  *
00111  * The fields op-code, tpa and tha have to be set prior to calling this function.
00112  */
00113 static void nip_arp_fill_defaults_and_send( nip_net_if_id_t if_id, struct ARP_PACKET *arp )
00114 {
00115         nip_net_if_t *net_if    = &nip_net_if_list[ if_id ];
00116         uint8_t      *ll_target = arp->tha;
00117 
00118         arp->hrd = htons( net_if->phy_conf.type );
00119         arp->pro = NIP_ARP_PR_TYPE;
00120         arp->hln = net_if->phy_conf.hw_addr_size;
00121         arp->pln = NIP_ARP_PR_SIZE;
00122         nip_memcpy( arp->sha, net_if->phy_conf.hw_addr, net_if->phy_conf.hw_addr_size );
00123         nip_memcpy( arp->spa, net_if->ip_conf.addr    , NIP_ARP_PR_SIZE );
00124 
00125         // ARP requests are always being broadcasted on the link layer
00126         if ( arp->op[1] == NIP_ARP_OP_REQUEST
00127 #if NIP_AUTOIP_ENABLE == 1
00128         // if sender IP address is link local address, always use link-layer
00129         // broadcast to transmit ARP packets.
00130         || ( arp->spa[0] == 169 && arp->spa[1] == 254 )
00131 #endif
00132         )
00133         {
00134                 ll_target = net_if->phy_conf.hw_brdcst_addr;
00135         }
00136 
00137         // send ARP packet
00138         net_if->phy_conf.hard_send_init(
00139                 if_id,
00140                 NULL,
00141                 NIP_NUM_PR_ARP,
00142                 ll_target,
00143                 arp->sha,
00144                 sizeof( struct ARP_PACKET )
00145         );
00146 
00147         net_if->phy_conf.hard_send( if_id, (uint8_t*)arp, sizeof( struct ARP_PACKET ) );
00148 }
00149 
00150 /** prepare ARP request packet. */
00151 static void nip_arp_fill_request( struct ARP_PACKET *arp, uint8_t *tpa )
00152 {
00153         nip_memset ( arp, 0, sizeof( struct ARP_PACKET ) );
00154         arp->op[1]  = NIP_ARP_OP_REQUEST;
00155         nip_memcpy( arp->tpa, tpa, NIP_ARP_PR_SIZE );
00156 }
00157 
00158 /** Find Transmission with status NIP_NET_IF_RESOLV_ADDR and process if time
00159  * for retransmission has come or address was found in cache.
00160  */
00161 void nip_arp_disp_resolve_any( void )
00162 {
00163         nip_net_trans_id_t id = 0;
00164         nip_net_if_trans_t *trans;
00165         struct ARP_CACHE   *cache;
00166 
00167 #if NIP_NET_MAX_TRANSMISSIONS > 1
00168         do
00169         {
00170 #endif
00171                 trans = &nip_net_trans_list[ id ];
00172                 if ( trans->status == NIP_NET_IF_RESOLV_ADDR )
00173                 {
00174                         if ( trans->time < nip_tickcount()
00175                           || NIP_SUCCESS == nip_arp_cache_lookup( trans->params.ip.ll_nw_addr, &cache ) )
00176                         {
00177                                 // because we cannot be sure that there won't be another transmission
00178                                 // waiting for address resolution, we'll set the flag for another
00179                                 // check.
00180                                 nip_disp_notify( NIP_DISP_CHECK_TRANS );
00181                                 nip_disp.next.common.trans = trans;
00182 
00183                                 // continue with ip_send command
00184                                 NIP_CURR_CMD = &nip_ip_disp_send;
00185                                 return;
00186                         }
00187                 }
00188 #if NIP_NET_MAX_TRANSMISSIONS > 1
00189         } while ( ++id < NIP_NET_MAX_TRANSMISSIONS );
00190 #endif
00191 }
00192 
00193 /** Retrieve hardware address from ARP cache or initiate ARP request
00194  *
00195  * The current transmission's status will be set to NIP_NET_IF_RTS and ip send
00196  * will be called upon successfull
00197  */
00198 void nip_arp_disp_resolve( void )
00199 {
00200         struct ARP_CACHE   *entry;
00201         struct ARP_PACKET  arp;
00202         nip_net_if_trans_t *trans = nip_disp.next.common.trans;
00203 
00204         // find entry in arp cache
00205         if ( NIP_SUCCESS == nip_arp_cache_lookup( trans->params.ip.ll_nw_addr, &entry ) )
00206         {
00207                 // return hardware address
00208                 nip_memcpy( nip_disp.next.common.remote_hw_addr, entry->hw_addr, NIP_ARP_HW_SIZE );
00209                 trans->status = NIP_NET_IF_RTS;
00210                 NIP_CURR_CMD = &nip_ip_disp_send;
00211         }
00212         else
00213         {
00214                 // update transmission
00215                 trans->retrans_cnt++;
00216                 trans->time = nip_tickcount() + NIP_ARP_RETRY_INTVL;
00217                 if ( trans->retrans_cnt > NIP_ARP_MAX_RETRIES )
00218                 {
00219                         trans->status = NIP_NET_IF_SEND_HNF;
00220                         NIP_CURR_CMD = &nip_ip_disp_send;
00221                 }
00222 
00223                 // build and send ARP request
00224                 nip_arp_fill_request( &arp, trans->params.ip.ll_nw_addr );
00225                 nip_arp_fill_defaults_and_send( trans->if_id, &arp );
00226         }
00227 }
00228 
00229 #if NIP_AUTOIP_ENABLE == 1
00230 
00231 /** Send ARP probe or announcement packet. IP address will be taken from AutoIP
00232  * configuration. The configured IP address of NIP_CURR_IF _has_ to be 0.0.0.0
00233  * for ARP probes, or the current link-local address for ARP announcements. In
00234  * the latter case it _has_ to match the address contained in the AutoIP-config.
00235  */
00236 void nip_arp_disp_probe_announcement( void )
00237 {
00238         struct ARP_PACKET arp;
00239 #if NIP_NET_IF_COUNT > 1
00240         struct nip_autoip_conf *conf   = & NIP_AUTOIP_CONF( NIP_CURR_IF );
00241         #define AUTOIP_CONF_ATTR(attr) conf-> attr
00242 #else
00243         #define AUTOIP_CONF_ATTR(attr) nip_autoip_conf.attr
00244 #endif
00245 
00246         // build and send ARP request
00247         nip_arp_fill_request( &arp, AUTOIP_CONF_ATTR(addr));
00248         nip_arp_fill_defaults_and_send( NIP_CURR_IF, &arp );
00249 }
00250 
00251 #endif /* NIP_AUTOIP_ENABLE */
00252 
00253 /** ARP Receive function to be called by dispatcher.
00254  *
00255  * This function will read and evaluate an ARP packet from the network interface
00256  * which's ID is given in the global nip_disp->param->if_id structure.*/
00257 void nip_disp_arp_receive( void )
00258 {
00259         // the following variables help reduce program memory usage big time
00260         // --> arp has local variables worth 37 Bytes.
00261 
00262         nip_net_if_id_t if_id   = NIP_CURR_IF;
00263         nip_net_if_t    *net_if = &nip_net_if_list[ if_id ];
00264         struct ARP_PACKET arp;
00265         struct ARP_CACHE *cache;
00266 
00267         // receive arp packet
00268         if ( sizeof( struct ARP_PACKET ) != net_if->phy_conf.hard_read( if_id, (uint8_t*) &arp, sizeof( struct ARP_PACKET ) ) )
00269         {
00270                 // There's something wrong with the packet. It's not large enough.
00271                 // --> forget about it!
00272                 return;
00273         }
00274 
00275         // check hardware type: Ethernet = 0x0001
00276         if ( ntohs(arp.hrd) != net_if->phy_conf.type )
00277                 return;
00278 
00279         // check protocol type: IP = 0x0800
00280         if ( arp.pro != NIP_ARP_PR_TYPE )
00281                 return;
00282 
00283         // read address sizes, Ethernet: 6, IP: 4
00284         if ( arp.hln != net_if->phy_conf.hw_addr_size || arp.pln != NIP_ARP_PR_SIZE )
00285                 return;
00286 
00287         if ( arp.op[0] == 0x00 )
00288         {
00289 #if NIP_AUTOIP_ENABLE == 1
00290                 // check ARP packet for IP address conflicts
00291                 nip_autoip_arpcheck( if_id, &arp );
00292 #endif
00293 
00294                 // check opcode: 0x0001 = Request
00295                 if ( arp.op[1] == NIP_ARP_OP_REQUEST )
00296                 {
00297                         // check ip
00298                         if ( nip_memcmp( arp.tpa, net_if->ip_conf.addr, 4) == 0  )
00299                         {
00300                                 // build reply
00301                                 nip_memcpy( arp.tha, arp.sha, NIP_ARP_PR_SIZE + net_if->phy_conf.hw_addr_size );
00302                                 arp.op[1]  = NIP_ARP_OP_REPLY;
00303 
00304                                 nip_arp_fill_defaults_and_send( NIP_CURR_IF, &arp );
00305                         }
00306                 }
00307                 // check opcode: 0x0002 = Response
00308                 else if ( arp.op[1] == NIP_ARP_OP_REPLY )
00309                 {
00310                         ///\todo check if we need to check arp.tpa at this point.
00311                         // add response to arp cache. The lookup function will either return
00312                         // the old cache entry for the given protocol address or will return
00313                         // a free slot where the address can be cached.
00314                         nip_arp_cache_lookup( arp.spa, &cache );
00315                         nip_memcpy( cache->hw_addr, arp.sha, arp.hln );
00316                         nip_memcpy( cache->pr_addr, arp.spa, arp.pln );
00317                         cache->timestamp = nip_tickcount() + NIP_ARP_CACHE_LIFE;
00318 
00319                         // check if the response helped any pending transmission
00320                         NIP_CURR_CMD = &nip_arp_disp_resolve_any;
00321                 }
00322         }
00323 }
00324 
00325 #endif /* NIP_ARP_ENABLE == 1 */

Generated on Thu Jul 10 01:09:29 2008 for NIP by  doxygen 1.5.5