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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [ethernet/] [lwIP_132/] [src/] [core/] [ipv4/] [icmp.c] - Blame information for rev 606

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 606 jeremybenn
/**
2
 * @file
3
 * ICMP - Internet Control Message Protocol
4
 *
5
 */
6
 
7
/*
8
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without modification,
12
 * are permitted provided that the following conditions are met:
13
 *
14
 * 1. Redistributions of source code must retain the above copyright notice,
15
 *    this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright notice,
17
 *    this list of conditions and the following disclaimer in the documentation
18
 *    and/or other materials provided with the distribution.
19
 * 3. The name of the author may not be used to endorse or promote products
20
 *    derived from this software without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31
 * OF SUCH DAMAGE.
32
 *
33
 * This file is part of the lwIP TCP/IP stack.
34
 *
35
 * Author: Adam Dunkels <adam@sics.se>
36
 *
37
 */
38
 
39
/* Some ICMP messages should be passed to the transport protocols. This
40
   is not implemented. */
41
 
42
#include "lwip/opt.h"
43
 
44
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
45
 
46
#include "lwip/icmp.h"
47
#include "lwip/inet.h"
48
#include "lwip/inet_chksum.h"
49
#include "lwip/ip.h"
50
#include "lwip/def.h"
51
#include "lwip/stats.h"
52
#include "lwip/snmp.h"
53
 
54
#include <string.h>
55
 
56
/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
57
 * used to modify and send a response packet (and to 1 if this is not the case,
58
 * e.g. when link header is stripped of when receiving) */
59
#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
60
#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
61
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
62
 
63
/* The amount of data from the original packet to return in a dest-unreachable */
64
#define ICMP_DEST_UNREACH_DATASIZE 8
65
 
66
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
67
 
68
/**
69
 * Processes ICMP input packets, called from ip_input().
70
 *
71
 * Currently only processes icmp echo requests and sends
72
 * out the echo response.
73
 *
74
 * @param p the icmp echo request packet, p->payload pointing to the ip header
75
 * @param inp the netif on which this packet was received
76
 */
77
void
78
icmp_input(struct pbuf *p, struct netif *inp)
79
{
80
  u8_t type;
81
#ifdef LWIP_DEBUG
82
  u8_t code;
83
#endif /* LWIP_DEBUG */
84
  struct icmp_echo_hdr *iecho;
85
  struct ip_hdr *iphdr;
86
  struct ip_addr tmpaddr;
87
  s16_t hlen;
88
 
89
  ICMP_STATS_INC(icmp.recv);
90
  snmp_inc_icmpinmsgs();
91
 
92
 
93
  iphdr = p->payload;
94
  hlen = IPH_HL(iphdr) * 4;
95
  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
96
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
97
    goto lenerr;
98
  }
99
 
100
  type = *((u8_t *)p->payload);
101
#ifdef LWIP_DEBUG
102
  code = *(((u8_t *)p->payload)+1);
103
#endif /* LWIP_DEBUG */
104
  switch (type) {
105
  case ICMP_ECHO:
106
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
107
    {
108
      int accepted = 1;
109
#if !LWIP_MULTICAST_PING
110
      /* multicast destination address? */
111
      if (ip_addr_ismulticast(&iphdr->dest)) {
112
        accepted = 0;
113
      }
114
#endif /* LWIP_MULTICAST_PING */
115
#if !LWIP_BROADCAST_PING
116
      /* broadcast destination address? */
117
      if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
118
        accepted = 0;
119
      }
120
#endif /* LWIP_BROADCAST_PING */
121
      /* broadcast or multicast destination address not acceptd? */
122
      if (!accepted) {
123
        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
124
        ICMP_STATS_INC(icmp.err);
125
        pbuf_free(p);
126
        return;
127
      }
128
    }
129
#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
130
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
131
    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
132
      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
133
      goto lenerr;
134
    }
135
    if (inet_chksum_pbuf(p) != 0) {
136
      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
137
      pbuf_free(p);
138
      ICMP_STATS_INC(icmp.chkerr);
139
      snmp_inc_icmpinerrors();
140
      return;
141
    }
142
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
143
    if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
144
      /* p is not big enough to contain link headers
145
       * allocate a new one and copy p into it
146
       */
147
      struct pbuf *r;
148
      /* switch p->payload to ip header */
149
      if (pbuf_header(p, hlen)) {
150
        LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
151
        goto memerr;
152
      }
153
      /* allocate new packet buffer with space for link headers */
154
      r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
155
      if (r == NULL) {
156
        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
157
        goto memerr;
158
      }
159
      LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
160
                  (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
161
      /* copy the whole packet including ip header */
162
      if (pbuf_copy(r, p) != ERR_OK) {
163
        LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
164
        goto memerr;
165
      }
166
      iphdr = r->payload;
167
      /* switch r->payload back to icmp header */
168
      if (pbuf_header(r, -hlen)) {
169
        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
170
        goto memerr;
171
      }
172
      /* free the original p */
173
      pbuf_free(p);
174
      /* we now have an identical copy of p that has room for link headers */
175
      p = r;
176
    } else {
177
      /* restore p->payload to point to icmp header */
178
      if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
179
        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
180
        goto memerr;
181
      }
182
    }
183
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
184
    /* At this point, all checks are OK. */
185
    /* We generate an answer by switching the dest and src ip addresses,
186
     * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
187
    iecho = p->payload;
188
    tmpaddr.addr = iphdr->src.addr;
189
    iphdr->src.addr = iphdr->dest.addr;
190
    iphdr->dest.addr = tmpaddr.addr;
191
    ICMPH_TYPE_SET(iecho, ICMP_ER);
192
    /* adjust the checksum */
193
    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
194
      iecho->chksum += htons(ICMP_ECHO << 8) + 1;
195
    } else {
196
      iecho->chksum += htons(ICMP_ECHO << 8);
197
    }
198
 
199
    /* Set the correct TTL and recalculate the header checksum. */
200
    IPH_TTL_SET(iphdr, ICMP_TTL);
201
    IPH_CHKSUM_SET(iphdr, 0);
202
#if CHECKSUM_GEN_IP
203
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
204
#endif /* CHECKSUM_GEN_IP */
205
 
206
    ICMP_STATS_INC(icmp.xmit);
207
    /* increase number of messages attempted to send */
208
    snmp_inc_icmpoutmsgs();
209
    /* increase number of echo replies attempted to send */
210
    snmp_inc_icmpoutechoreps();
211
 
212
    if(pbuf_header(p, hlen)) {
213
      LWIP_ASSERT("Can't move over header in packet", 0);
214
    } else {
215
      err_t ret;
216
      ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
217
                   ICMP_TTL, 0, IP_PROTO_ICMP, inp);
218
      if (ret != ERR_OK) {
219
        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
220
      }
221
    }
222
    break;
223
  default:
224
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
225
                (s16_t)type, (s16_t)code));
226
    ICMP_STATS_INC(icmp.proterr);
227
    ICMP_STATS_INC(icmp.drop);
228
  }
229
  pbuf_free(p);
230
  return;
231
lenerr:
232
  pbuf_free(p);
233
  ICMP_STATS_INC(icmp.lenerr);
234
  snmp_inc_icmpinerrors();
235
  return;
236
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
237
memerr:
238
  pbuf_free(p);
239
  ICMP_STATS_INC(icmp.err);
240
  snmp_inc_icmpinerrors();
241
  return;
242
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
243
}
244
 
245
/**
246
 * Send an icmp 'destination unreachable' packet, called from ip_input() if
247
 * the transport layer protocol is unknown and from udp_input() if the local
248
 * port is not bound.
249
 *
250
 * @param p the input packet for which the 'unreachable' should be sent,
251
 *          p->payload pointing to the IP header
252
 * @param t type of the 'unreachable' packet
253
 */
254
void
255
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
256
{
257
  icmp_send_response(p, ICMP_DUR, t);
258
}
259
 
260
#if IP_FORWARD || IP_REASSEMBLY
261
/**
262
 * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
263
 *
264
 * @param p the input packet for which the 'time exceeded' should be sent,
265
 *          p->payload pointing to the IP header
266
 * @param t type of the 'time exceeded' packet
267
 */
268
void
269
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
270
{
271
  icmp_send_response(p, ICMP_TE, t);
272
}
273
 
274
#endif /* IP_FORWARD || IP_REASSEMBLY */
275
 
276
/**
277
 * Send an icmp packet in response to an incoming packet.
278
 *
279
 * @param p the input packet for which the 'unreachable' should be sent,
280
 *          p->payload pointing to the IP header
281
 * @param type Type of the ICMP header
282
 * @param code Code of the ICMP header
283
 */
284
static void
285
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
286
{
287
  struct pbuf *q;
288
  struct ip_hdr *iphdr;
289
  /* we can use the echo header here */
290
  struct icmp_echo_hdr *icmphdr;
291
 
292
  /* ICMP header + IP header + 8 bytes of data */
293
  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
294
                 PBUF_RAM);
295
  if (q == NULL) {
296
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
297
    return;
298
  }
299
  LWIP_ASSERT("check that first pbuf can hold icmp message",
300
             (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
301
 
302
  iphdr = p->payload;
303
  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
304
  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
305
  LWIP_DEBUGF(ICMP_DEBUG, (" to "));
306
  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
307
  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
308
 
309
  icmphdr = q->payload;
310
  icmphdr->type = type;
311
  icmphdr->code = code;
312
  icmphdr->id = 0;
313
  icmphdr->seqno = 0;
314
 
315
  /* copy fields from original packet */
316
  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
317
          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
318
 
319
  /* calculate checksum */
320
  icmphdr->chksum = 0;
321
  icmphdr->chksum = inet_chksum(icmphdr, q->len);
322
  ICMP_STATS_INC(icmp.xmit);
323
  /* increase number of messages attempted to send */
324
  snmp_inc_icmpoutmsgs();
325
  /* increase number of destination unreachable messages attempted to send */
326
  snmp_inc_icmpouttimeexcds();
327
  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
328
  pbuf_free(q);
329
}
330
 
331
#endif /* LWIP_ICMP */

powered by: WebSVN 2.1.0

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