OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [ethernet/] [lwIP/] [netif/] [etharp.c] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 606 jeremybenn
/**
2
 * @file
3
 * Address Resolution Protocol module for IP over Ethernet
4
 *
5
 * Functionally, ARP is divided into two parts. The first maps an IP address
6
 * to a physical address when sending a packet, and the second part answers
7
 * requests from other machines for our physical address.
8
 *
9
 * This implementation complies with RFC 826 (Ethernet ARP). It supports
10
 * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
11
 * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon
12
 * address change.
13
 */
14
 
15
/*
16
 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
17
 * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
18
 * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
19
 * All rights reserved.
20
 *
21
 * Redistribution and use in source and binary forms, with or without modification,
22
 * are permitted provided that the following conditions are met:
23
 *
24
 * 1. Redistributions of source code must retain the above copyright notice,
25
 *    this list of conditions and the following disclaimer.
26
 * 2. Redistributions in binary form must reproduce the above copyright notice,
27
 *    this list of conditions and the following disclaimer in the documentation
28
 *    and/or other materials provided with the distribution.
29
 * 3. The name of the author may not be used to endorse or promote products
30
 *    derived from this software without specific prior written permission.
31
 *
32
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
33
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
34
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
35
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
37
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
41
 * OF SUCH DAMAGE.
42
 *
43
 * This file is part of the lwIP TCP/IP stack.
44
 *
45
 */
46
#include <string.h>
47
#include "lwip/opt.h"
48
#include "lwip/inet.h"
49
#include "netif/etharp.h"
50
#include "lwip/ip.h"
51
#include "lwip/stats.h"
52
#include "lwip/snmp.h"
53
 
54
/* ARP needs to inform DHCP of any ARP replies? */
55
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
56
#  include "lwip/dhcp.h"
57
#endif
58
 
59
/** the time an ARP entry stays valid after its last update,
60
 * (240 * 5) seconds = 20 minutes.
61
 */
62
#define ARP_MAXAGE 240
63
/** the time an ARP entry stays pending after first request,
64
 * (2 * 5) seconds = 10 seconds.
65
 *
66
 * @internal Keep this number at least 2, otherwise it might
67
 * run out instantly if the timeout occurs directly after a request.
68
 */
69
#define ARP_MAXPENDING 2
70
 
71
#define HWTYPE_ETHERNET 1
72
 
73
/** ARP message types */
74
#define ARP_REQUEST 1
75
#define ARP_REPLY 2
76
 
77
#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
78
#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
79
 
80
#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
81
#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
82
 
83
enum etharp_state {
84
  ETHARP_STATE_EMPTY,
85
  ETHARP_STATE_PENDING,
86
  ETHARP_STATE_STABLE,
87
  /** @internal transitional state used in etharp_tmr() for convenience*/
88
  ETHARP_STATE_EXPIRED
89
};
90
 
91
struct etharp_entry {
92
#if ARP_QUEUEING
93
  /**
94
   * Pointer to queue of pending outgoing packets on this ARP entry.
95
   */
96
   struct pbuf *p;
97
#endif
98
  struct ip_addr ipaddr;
99
  struct eth_addr ethaddr;
100
  enum etharp_state state;
101
  u8_t ctime;
102
  struct netif *netif;
103
};
104
 
105
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
106
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
107
 
108
/**
109
 * Try hard to create a new entry - we want the IP address to appear in
110
 * the cache (even if this means removing an active entry or so). */
111
#define ETHARP_TRY_HARD 1
112
 
113
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
114
static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
115
/**
116
 * Initializes ARP module.
117
 */
118
void
119
etharp_init(void)
120
{
121
  u8_t i;
122
  /* clear ARP entries */
123
  for(i = 0; i < ARP_TABLE_SIZE; ++i) {
124
    arp_table[i].state = ETHARP_STATE_EMPTY;
125
#if ARP_QUEUEING
126
    arp_table[i].p = NULL;
127
#endif
128
    arp_table[i].ctime = 0;
129
    arp_table[i].netif = NULL;
130
  }
131
}
132
 
133
/**
134
 * Clears expired entries in the ARP table.
135
 *
136
 * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
137
 * in order to expire entries in the ARP table.
138
 */
139
void
140
etharp_tmr(void)
141
{
142
  u8_t i;
143
 
144
  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
145
  /* remove expired entries from the ARP table */
146
  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
147
    arp_table[i].ctime++;
148
    /* stable entry? */
149
    if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
150
         /* entry has become old? */
151
        (arp_table[i].ctime >= ARP_MAXAGE)) {
152
      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %"U16_F".\n", (u16_t)i));
153
      arp_table[i].state = ETHARP_STATE_EXPIRED;
154
    /* pending entry? */
155
    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
156
      /* entry unresolved/pending for too long? */
157
      if (arp_table[i].ctime >= ARP_MAXPENDING) {
158
        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i));
159
        arp_table[i].state = ETHARP_STATE_EXPIRED;
160
#if ARP_QUEUEING
161
      } else if (arp_table[i].p != NULL) {
162
        /* resend an ARP query here */
163
#endif
164
      }
165
    }
166
    /* clean up entries that have just been expired */
167
    if (arp_table[i].state == ETHARP_STATE_EXPIRED) {
168
      /* remove from SNMP ARP index tree */
169
      snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
170
#if ARP_QUEUEING
171
      /* and empty packet queue */
172
      if (arp_table[i].p != NULL) {
173
        /* remove all queued packets */
174
        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].p)));
175
        pbuf_free(arp_table[i].p);
176
        arp_table[i].p = NULL;
177
      }
178
#endif
179
      /* recycle entry for re-use */
180
      arp_table[i].state = ETHARP_STATE_EMPTY;
181
    }
182
  }
183
}
184
 
185
/**
186
 * Search the ARP table for a matching or new entry.
187
 *
188
 * If an IP address is given, return a pending or stable ARP entry that matches
189
 * the address. If no match is found, create a new entry with this address set,
190
 * but in state ETHARP_EMPTY. The caller must check and possibly change the
191
 * state of the returned entry.
192
 *
193
 * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
194
 *
195
 * In all cases, attempt to create new entries from an empty entry. If no
196
 * empty entries are available and ETHARP_TRY_HARD flag is set, recycle
197
 * old entries. Heuristic choose the least important entry for recycling.
198
 *
199
 * @param ipaddr IP address to find in ARP cache, or to add if not found.
200
 * @param flags
201
 * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
202
 * active (stable or pending) entries.
203
 *
204
 * @return The ARP entry index that matched or is created, ERR_MEM if no
205
 * entry is found or could be recycled.
206
 */
207
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
208
{
209
  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
210
  s8_t empty = ARP_TABLE_SIZE;
211
  u8_t i = 0, age_pending = 0, age_stable = 0;
212
#if ARP_QUEUEING
213
  /* oldest entry with packets on queue */
214
  s8_t old_queue = ARP_TABLE_SIZE;
215
  /* its age */
216
  u8_t age_queue = 0;
217
#endif
218
 
219
  /**
220
   * a) do a search through the cache, remember candidates
221
   * b) select candidate entry
222
   * c) create new entry
223
   */
224
 
225
  /* a) in a single search sweep, do all of this
226
   * 1) remember the first empty entry (if any)
227
   * 2) remember the oldest stable entry (if any)
228
   * 3) remember the oldest pending entry without queued packets (if any)
229
   * 4) remember the oldest pending entry with queued packets (if any)
230
   * 5) search for a matching IP entry, either pending or stable
231
   *    until 5 matches, or all entries are searched for.
232
   */
233
 
234
  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
235
    /* no empty entry found yet and now we do find one? */
236
    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {
237
      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
238
      /* remember first empty entry */
239
      empty = i;
240
    }
241
    /* pending entry? */
242
    else if (arp_table[i].state == ETHARP_STATE_PENDING) {
243
      /* if given, does IP address match IP address in ARP entry? */
244
      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
245
        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));
246
        /* found exact IP address match, simply bail out */
247
        return i;
248
#if ARP_QUEUEING
249
      /* pending with queued packets? */
250
      } else if (arp_table[i].p != NULL) {
251
        if (arp_table[i].ctime >= age_queue) {
252
          old_queue = i;
253
          age_queue = arp_table[i].ctime;
254
        }
255
#endif
256
      /* pending without queued packets? */
257
      } else {
258
        if (arp_table[i].ctime >= age_pending) {
259
          old_pending = i;
260
          age_pending = arp_table[i].ctime;
261
        }
262
      }
263
    }
264
    /* stable entry? */
265
    else if (arp_table[i].state == ETHARP_STATE_STABLE) {
266
      /* if given, does IP address match IP address in ARP entry? */
267
      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
268
        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));
269
        /* found exact IP address match, simply bail out */
270
        return i;
271
      /* remember entry with oldest stable entry in oldest, its age in maxtime */
272
      } else if (arp_table[i].ctime >= age_stable) {
273
        old_stable = i;
274
        age_stable = arp_table[i].ctime;
275
      }
276
    }
277
  }
278
  /* { we have no match } => try to create a new entry */
279
 
280
  /* no empty entry found and not allowed to recycle? */
281
  if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))
282
  {
283
    return (s8_t)ERR_MEM;
284
  }
285
 
286
  /* b) choose the least destructive entry to recycle:
287
   * 1) empty entry
288
   * 2) oldest stable entry
289
   * 3) oldest pending entry without queued packets
290
   * 4) oldest pending entry without queued packets
291
   *
292
   * { ETHARP_TRY_HARD is set at this point }
293
   */
294
 
295
  /* 1) empty entry available? */
296
  if (empty < ARP_TABLE_SIZE) {
297
    i = empty;
298
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
299
  }
300
  /* 2) found recyclable stable entry? */
301
  else if (old_stable < ARP_TABLE_SIZE) {
302
    /* recycle oldest stable*/
303
    i = old_stable;
304
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
305
#if ARP_QUEUEING
306
    /* no queued packets should exist on stable entries */
307
    LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);
308
#endif
309
  /* 3) found recyclable pending entry without queued packets? */
310
  } else if (old_pending < ARP_TABLE_SIZE) {
311
    /* recycle oldest pending */
312
    i = old_pending;
313
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
314
#if ARP_QUEUEING
315
  /* 4) found recyclable pending entry with queued packets? */
316
  } else if (old_queue < ARP_TABLE_SIZE) {
317
    /* recycle oldest pending */
318
    i = old_queue;
319
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].p)));
320
    pbuf_free(arp_table[i].p);
321
    arp_table[i].p = NULL;
322
#endif
323
    /* no empty or recyclable entries found */
324
  } else {
325
    return (s8_t)ERR_MEM;
326
  }
327
 
328
  /* { empty or recyclable entry found } */
329
  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
330
 
331
  if (arp_table[i].state != ETHARP_STATE_EMPTY)
332
  {
333
    snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
334
  }
335
  /* recycle entry (no-op for an already empty entry) */
336
  arp_table[i].state = ETHARP_STATE_EMPTY;
337
 
338
  /* IP address given? */
339
  if (ipaddr != NULL) {
340
    /* set IP address */
341
    ip_addr_set(&arp_table[i].ipaddr, ipaddr);
342
  }
343
  arp_table[i].ctime = 0;
344
  return (err_t)i;
345
}
346
 
347
/**
348
 * Update (or insert) a IP/MAC address pair in the ARP cache.
349
 *
350
 * If a pending entry is resolved, any queued packets will be sent
351
 * at this point.
352
 *
353
 * @param ipaddr IP address of the inserted ARP entry.
354
 * @param ethaddr Ethernet address of the inserted ARP entry.
355
 * @param flags Defines behaviour:
356
 * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
357
 * only existing ARP entries will be updated.
358
 *
359
 * @return
360
 * - ERR_OK Succesfully updated ARP cache.
361
 * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
362
 * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
363
 *
364
 * @see pbuf_free()
365
 */
366
static err_t
367
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
368
{
369
  s8_t i;
370
  u8_t k;
371
  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));
372
  LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0);
373
  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
374
                                        ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),
375
                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
376
                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
377
  /* non-unicast address? */
378
  if (ip_addr_isany(ipaddr) ||
379
      ip_addr_isbroadcast(ipaddr, netif) ||
380
      ip_addr_ismulticast(ipaddr)) {
381
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
382
    return ERR_ARG;
383
  }
384
  /* find or create ARP entry */
385
  i = find_entry(ipaddr, flags);
386
  /* bail out if no entry could be found */
387
  if (i < 0) return (err_t)i;
388
 
389
  /* mark it stable */
390
  arp_table[i].state = ETHARP_STATE_STABLE;
391
  /* record network interface */
392
  arp_table[i].netif = netif;
393
 
394
  /* insert in SNMP ARP index tree */
395
  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
396
 
397
  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
398
  /* update address */
399
  k = netif->hwaddr_len;
400
  while (k > 0) {
401
    k--;
402
    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
403
  }
404
  /* reset time stamp */
405
  arp_table[i].ctime = 0;
406
/* this is where we will send out queued packets! */
407
#if ARP_QUEUEING
408
  while (arp_table[i].p != NULL) {
409
    /* get the first packet on the queue */
410
    struct pbuf *p = arp_table[i].p;
411
    /* Ethernet header */
412
    struct eth_hdr *ethhdr = p->payload;
413
    /* remember (and reference) remainder of queue */
414
    /* note: this will also terminate the p pbuf chain */
415
    arp_table[i].p = pbuf_dequeue(p);
416
    /* fill-in Ethernet header */
417
    k = netif->hwaddr_len;
418
    while(k > 0) {
419
      k--;
420
      ethhdr->dest.addr[k] = ethaddr->addr[k];
421
      ethhdr->src.addr[k] = netif->hwaddr[k];
422
    }
423
    ethhdr->type = htons(ETHTYPE_IP);
424
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
425
    /* send the queued IP packet */
426
    netif->linkoutput(netif, p);
427
    /* free the queued IP packet */
428
    pbuf_free(p);
429
  }
430
#endif
431
  return ERR_OK;
432
}
433
 
434
/**
435
 * Finds (stable) ethernet/IP address pair from ARP table
436
 * using interface and IP address index.
437
 * @note the addresses in the ARP table are in network order!
438
 *
439
 * @param netif points to interface index
440
 * @param ipaddr points to the (network order) IP address index
441
 * @param eth_ret points to return pointer
442
 * @param ip_ret points to return pointer
443
 * @return table index if found, -1 otherwise
444
 */
445
s8_t
446
etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,
447
         struct eth_addr **eth_ret, struct ip_addr **ip_ret)
448
{
449
  s8_t i;
450
 
451
  i = 0;
452
  while (i < ARP_TABLE_SIZE)
453
  {
454
    if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
455
        (arp_table[i].netif == netif) &&
456
        ip_addr_cmp(ipaddr, &arp_table[i].ipaddr) )
457
    {
458
      *eth_ret = &arp_table[i].ethaddr;
459
      *ip_ret = &arp_table[i].ipaddr;
460
      return i;
461
    }
462
    i++;
463
  }
464
  return -1;
465
}
466
 
467
/**
468
 * Updates the ARP table using the given IP packet.
469
 *
470
 * Uses the incoming IP packet's source address to update the
471
 * ARP cache for the local network. The function does not alter
472
 * or free the packet. This function must be called before the
473
 * packet p is passed to the IP layer.
474
 *
475
 * @param netif The lwIP network interface on which the IP packet pbuf arrived.
476
 * @param pbuf The IP packet that arrived on netif.
477
 *
478
 * @return NULL
479
 *
480
 * @see pbuf_free()
481
 */
482
void
483
etharp_ip_input(struct netif *netif, struct pbuf *p)
484
{
485
  struct ethip_hdr *hdr;
486
  LWIP_ASSERT("netif != NULL", netif != NULL);
487
  /* Only insert an entry if the source IP address of the
488
     incoming IP packet comes from a host on the local network. */
489
  hdr = p->payload;
490
  /* source is not on the local network? */
491
  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
492
    /* do nothing */
493
    return;
494
  }
495
 
496
  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
497
  /* update ARP table */
498
  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
499
   * back soon (for example, if the destination IP address is ours. */
500
  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
501
}
502
 
503
 
504
/**
505
 * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
506
 * send out queued IP packets. Updates cache with snooped address pairs.
507
 *
508
 * Should be called for incoming ARP packets. The pbuf in the argument
509
 * is freed by this function.
510
 *
511
 * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
512
 * @param pbuf The ARP packet that arrived on netif. Is freed by this function.
513
 * @param ethaddr Ethernet address of netif.
514
 *
515
 * @return NULL
516
 *
517
 * @see pbuf_free()
518
 */
519
void
520
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
521
{
522
  struct etharp_hdr *hdr;
523
  /* these are aligned properly, whereas the ARP header fields might not be */
524
  struct ip_addr sipaddr, dipaddr;
525
  u8_t i;
526
  u8_t for_us;
527
 
528
  LWIP_ASSERT("netif != NULL", netif != NULL);
529
 
530
  /* drop short ARP packets */
531
  if (p->tot_len < sizeof(struct etharp_hdr)) {
532
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr)));
533
    pbuf_free(p);
534
    return;
535
  }
536
 
537
  hdr = p->payload;
538
 
539
  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
540
   * structure packing (not using structure copy which breaks strict-aliasing rules). */
541
  memcpy(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
542
  memcpy(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
543
 
544
  /* this interface is not configured? */
545
  if (netif->ip_addr.addr == 0) {
546
    for_us = 0;
547
  } else {
548
    /* ARP packet directed to us? */
549
    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));
550
  }
551
 
552
  /* ARP message directed to us? */
553
  if (for_us) {
554
    /* add IP address in ARP cache; assume requester wants to talk to us.
555
     * can result in directly sending the queued packets for this host. */
556
    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
557
  /* ARP message not directed to us? */
558
  } else {
559
    /* update the source IP address in the cache, if present */
560
    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
561
  }
562
 
563
  /* now act on the message itself */
564
  switch (htons(hdr->opcode)) {
565
  /* ARP request? */
566
  case ARP_REQUEST:
567
    /* ARP request. If it asked for our address, we send out a
568
     * reply. In any case, we time-stamp any existing ARP entry,
569
     * and possiby send out an IP packet that was queued on it. */
570
 
571
    LWIP_DEBUGF (ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
572
    /* ARP request for our address? */
573
    if (for_us) {
574
 
575
      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
576
      /* re-use pbuf to send ARP reply */
577
      hdr->opcode = htons(ARP_REPLY);
578
 
579
      hdr->dipaddr = hdr->sipaddr;
580
      hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
581
 
582
      i = netif->hwaddr_len;
583
      while(i > 0) {
584
        i--;
585
        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
586
        hdr->shwaddr.addr[i] = ethaddr->addr[i];
587
        hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
588
        hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
589
      }
590
 
591
      hdr->hwtype = htons(HWTYPE_ETHERNET);
592
      ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
593
 
594
      hdr->proto = htons(ETHTYPE_IP);
595
      ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
596
 
597
      hdr->ethhdr.type = htons(ETHTYPE_ARP);
598
      /* return ARP reply */
599
      netif->linkoutput(netif, p);
600
    /* we are not configured? */
601
    } else if (netif->ip_addr.addr == 0) {
602
      /* { for_us == 0 and netif->ip_addr.addr == 0 } */
603
      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
604
    /* request was not directed to us */
605
    } else {
606
      /* { for_us == 0 and netif->ip_addr.addr != 0 } */
607
      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
608
    }
609
    break;
610
  case ARP_REPLY:
611
    /* ARP reply. We already updated the ARP cache earlier. */
612
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
613
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
614
    /* DHCP wants to know about ARP replies from any host with an
615
     * IP address also offered to us by the DHCP server. We do not
616
     * want to take a duplicate IP address on a single network.
617
     * @todo How should we handle redundant (fail-over) interfaces?
618
     * */
619
    dhcp_arp_reply(netif, &sipaddr);
620
#endif
621
    break;
622
  default:
623
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
624
    break;
625
  }
626
  /* free ARP packet */
627
  pbuf_free(p);
628
}
629
 
630
/**
631
 * Resolve and fill-in Ethernet address header for outgoing packet.
632
 *
633
 * For IP multicast and broadcast, corresponding Ethernet addresses
634
 * are selected and the packet is transmitted on the link.
635
 *
636
 * For unicast addresses, the packet is submitted to etharp_query(). In
637
 * case the IP address is outside the local network, the IP address of
638
 * the gateway is used.
639
 *
640
 * @param netif The lwIP network interface which the IP packet will be sent on.
641
 * @param ipaddr The IP address of the packet destination.
642
 * @param pbuf The pbuf(s) containing the IP packet to be sent.
643
 *
644
 * @return
645
 * - ERR_RTE No route to destination (no gateway to external networks),
646
 * or the return type of either etharp_query() or netif->linkoutput().
647
 */
648
err_t
649
etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
650
{
651
  struct eth_addr *dest, *srcaddr, mcastaddr;
652
  struct eth_hdr *ethhdr;
653
  u8_t i;
654
 
655
  /* make room for Ethernet header - should not fail */
656
  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
657
    /* bail out */
658
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
659
    LINK_STATS_INC(link.lenerr);
660
    return ERR_BUF;
661
  }
662
 
663
  /* assume unresolved Ethernet address */
664
  dest = NULL;
665
  /* Determine on destination hardware address. Broadcasts and multicasts
666
   * are special, other IP addresses are looked up in the ARP table. */
667
 
668
  /* broadcast destination IP address? */
669
  if (ip_addr_isbroadcast(ipaddr, netif)) {
670
    /* broadcast on Ethernet also */
671
    dest = (struct eth_addr *)&ethbroadcast;
672
  /* multicast destination IP address? */
673
  } else if (ip_addr_ismulticast(ipaddr)) {
674
    /* Hash IP multicast address to MAC address.*/
675
    mcastaddr.addr[0] = 0x01;
676
    mcastaddr.addr[1] = 0x00;
677
    mcastaddr.addr[2] = 0x5e;
678
    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
679
    mcastaddr.addr[4] = ip4_addr3(ipaddr);
680
    mcastaddr.addr[5] = ip4_addr4(ipaddr);
681
    /* destination Ethernet address is multicast */
682
    dest = &mcastaddr;
683
  /* unicast destination IP address? */
684
  } else {
685
    /* outside local network? */
686
    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
687
      /* interface has default gateway? */
688
      if (netif->gw.addr != 0) {
689
        /* send to hardware address of default gateway IP address */
690
        ipaddr = &(netif->gw);
691
      /* no default gateway available */
692
      } else {
693
        /* no route to destination error (default gateway missing) */
694
        return ERR_RTE;
695
      }
696
    }
697
    /* queue on destination Ethernet address belonging to ipaddr */
698
    return etharp_query(netif, ipaddr, q);
699
  }
700
 
701
  /* continuation for multicast/broadcast destinations */
702
  /* obtain source Ethernet address of the given interface */
703
  srcaddr = (struct eth_addr *)netif->hwaddr;
704
  ethhdr = q->payload;
705
  i = netif->hwaddr_len;
706
  while(i > 0) {
707
    i--;
708
    ethhdr->dest.addr[i] = dest->addr[i];
709
    ethhdr->src.addr[i] = srcaddr->addr[i];
710
  }
711
  ethhdr->type = htons(ETHTYPE_IP);
712
  /* send packet directly on the link */
713
  return netif->linkoutput(netif, q);
714
}
715
 
716
/**
717
 * Send an ARP request for the given IP address and/or queue a packet.
718
 *
719
 * If the IP address was not yet in the cache, a pending ARP cache entry
720
 * is added and an ARP request is sent for the given address. The packet
721
 * is queued on this entry.
722
 *
723
 * If the IP address was already pending in the cache, a new ARP request
724
 * is sent for the given address. The packet is queued on this entry.
725
 *
726
 * If the IP address was already stable in the cache, and a packet is
727
 * given, it is directly sent and no ARP request is sent out.
728
 *
729
 * If the IP address was already stable in the cache, and no packet is
730
 * given, an ARP request is sent out.
731
 *
732
 * @param netif The lwIP network interface on which ipaddr
733
 * must be queried for.
734
 * @param ipaddr The IP address to be resolved.
735
 * @param q If non-NULL, a pbuf that must be delivered to the IP address.
736
 * q is not freed by this function.
737
 *
738
 * @return
739
 * - ERR_BUF Could not make room for Ethernet header.
740
 * - ERR_MEM Hardware address unknown, and no more ARP entries available
741
 *   to query for address or queue the packet.
742
 * - ERR_MEM Could not queue packet due to memory shortage.
743
 * - ERR_RTE No route to destination (no gateway to external networks).
744
 * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
745
 *
746
 */
747
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
748
{
749
  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
750
  err_t result = ERR_MEM;
751
  s8_t i; /* ARP entry index */
752
  u8_t k; /* Ethernet address octet index */
753
 
754
  /* non-unicast address? */
755
  if (ip_addr_isbroadcast(ipaddr, netif) ||
756
      ip_addr_ismulticast(ipaddr) ||
757
      ip_addr_isany(ipaddr)) {
758
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
759
    return ERR_ARG;
760
  }
761
 
762
  /* find entry in ARP cache, ask to create entry if queueing packet */
763
  i = find_entry(ipaddr, ETHARP_TRY_HARD);
764
 
765
  /* could not find or create entry? */
766
  if (i < 0)
767
  {
768
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
769
    if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));
770
    return (err_t)i;
771
  }
772
 
773
  /* mark a fresh entry as pending (we just sent a request) */
774
  if (arp_table[i].state == ETHARP_STATE_EMPTY) {
775
    arp_table[i].state = ETHARP_STATE_PENDING;
776
  }
777
 
778
  /* { i is either a STABLE or (new or existing) PENDING entry } */
779
  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
780
  ((arp_table[i].state == ETHARP_STATE_PENDING) ||
781
   (arp_table[i].state == ETHARP_STATE_STABLE)));
782
 
783
  /* do we have a pending entry? or an implicit query request? */
784
  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
785
    /* try to resolve it; send out ARP request */
786
    result = etharp_request(netif, ipaddr);
787
  }
788
 
789
  /* packet given? */
790
  if (q != NULL) {
791
    /* stable entry? */
792
    if (arp_table[i].state == ETHARP_STATE_STABLE) {
793
      /* we have a valid IP->Ethernet address mapping,
794
       * fill in the Ethernet header for the outgoing packet */
795
      struct eth_hdr *ethhdr = q->payload;
796
      k = netif->hwaddr_len;
797
      while(k > 0) {
798
        k--;
799
        ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
800
        ethhdr->src.addr[k]  = srcaddr->addr[k];
801
      }
802
      ethhdr->type = htons(ETHTYPE_IP);
803
      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));
804
      /* send the packet */
805
      result = netif->linkoutput(netif, q);
806
    /* pending entry? (either just created or already pending */
807
    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
808
#if ARP_QUEUEING /* queue the given q packet */
809
      struct pbuf *p;
810
      /* copy any PBUF_REF referenced payloads into PBUF_RAM */
811
      /* (the caller of lwIP assumes the referenced payload can be
812
       * freed after it returns from the lwIP call that brought us here) */
813
      p = pbuf_take(q);
814
      /* packet could be taken over? */
815
      if (p != NULL) {
816
        /* queue packet ... */
817
        if (arp_table[i].p == NULL) {
818
          /* ... in the empty queue */
819
          pbuf_ref(p);
820
          arp_table[i].p = p;
821
#if 0 /* multi-packet-queueing disabled, see bug #11400 */
822
        } else {
823
          /* ... at tail of non-empty queue */
824
          pbuf_queue(arp_table[i].p, p);
825
#endif
826
        }
827
        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
828
        result = ERR_OK;
829
      } else {
830
        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
831
        /* { result == ERR_MEM } through initialization */
832
      }
833
#else /* ARP_QUEUEING == 0 */
834
      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
835
      /* { result == ERR_MEM } through initialization */
836
      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
837
#endif
838
    }
839
  }
840
  return result;
841
}
842
 
843
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)
844
{
845
  struct pbuf *p;
846
  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
847
  err_t result = ERR_OK;
848
  u8_t k; /* ARP entry index */
849
 
850
  /* allocate a pbuf for the outgoing ARP request packet */
851
  p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
852
  /* could allocate a pbuf for an ARP request? */
853
  if (p != NULL) {
854
    struct etharp_hdr *hdr = p->payload;
855
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));
856
    hdr->opcode = htons(ARP_REQUEST);
857
    k = netif->hwaddr_len;
858
    while(k > 0) {
859
      k--;
860
      hdr->shwaddr.addr[k] = srcaddr->addr[k];
861
      /* the hardware address is what we ask for, in
862
       * a request it is a don't-care value, we use zeroes */
863
      hdr->dhwaddr.addr[k] = 0x00;
864
    }
865
    hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
866
    hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
867
 
868
    hdr->hwtype = htons(HWTYPE_ETHERNET);
869
    ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
870
 
871
    hdr->proto = htons(ETHTYPE_IP);
872
    ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
873
    k = netif->hwaddr_len;
874
    while(k > 0) {
875
      k--;
876
      /* broadcast to all network interfaces on the local network */
877
      hdr->ethhdr.dest.addr[k] = 0xff;
878
      hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
879
    }
880
    hdr->ethhdr.type = htons(ETHTYPE_ARP);
881
    /* send ARP query */
882
    result = netif->linkoutput(netif, p);
883
    /* free ARP query packet */
884
    pbuf_free(p);
885
    p = NULL;
886
  /* could not allocate pbuf for ARP request */
887
  } else {
888
    result = ERR_MEM;
889
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));
890
  }
891
  return result;
892
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.