Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / apps / ping.c
1 /**
2  * @file
3  * Ping sender module
4  *
5  */
6
7 /*
8  * Redistribution and use in source and binary forms, with or without modification, 
9  * are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission. 
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
22  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
28  * OF SUCH DAMAGE.
29  *
30  * This file is part of the lwIP TCP/IP stack.
31  * 
32  */
33
34 /** 
35  * This is an example of a "ping" sender (with raw API and socket API).
36  * It can be used as a start point to maintain opened a network connection, or
37  * like a network "watchdog" for your device.
38  *
39  */
40
41 #include "lwip/opt.h"
42
43 #if LWIP_RAW && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
44
45 #include "lwip/mem.h"
46 #include "lwip/raw.h"
47 #include "lwip/icmp.h"
48 #include "lwip/netif.h"
49 #include "lwip/sys.h"
50 #include "lwip/sockets.h"
51 #include "lwip/inet.h"
52 #include "lwip/inet_chksum.h"
53
54 #include "apps/ping.h"
55
56 #include <geekos/timer.h>
57 #include <geekos/ktypes.h>
58
59 /**
60  * PING_DEBUG: Enable debugging for PING.
61  */
62 #ifndef PING_DEBUG
63 #define PING_DEBUG     LWIP_DBG_ON
64 #endif
65
66 /** ping target - should be a "struct ip_addr" */
67 #ifndef PING_TARGET
68 #define PING_TARGET   (netif_default?netif_default->gw:ip_addr_any)
69 #endif
70
71 /** ping receive timeout - in milliseconds */
72 #ifndef PING_RCV_TIMEO
73 #define PING_RCV_TIMEO 1000
74 #endif
75
76 /** ping delay - in milliseconds */
77 #ifndef PING_DELAY
78 #define PING_DELAY     1000
79 #endif
80
81 /** ping identifier - must fit on a u16_t */
82 #ifndef PING_ID
83 #define PING_ID        0xAFAF
84 #endif
85
86 /** ping additional data size to include in the packet */
87 #ifndef PING_DATA_SIZE
88 #define PING_DATA_SIZE 32
89 #endif
90
91 /** ping result action - no default action */
92 #ifndef PING_RESULT
93 #define PING_RESULT(ping_ok)
94 #endif
95
96 /* ping variables */
97 static u16_t ping_seq_num;
98 static u32_t ping_time;
99
100 #if NO_SYS
101 /* port-defined functions used for timer execution */
102 void sys_msleep(u32_t ms);
103 u32_t sys_now();
104 #endif /* NO_SYS */
105
106 /** Prepare a echo ICMP request */
107 static void
108 ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
109 {
110   int i;
111
112   ICMPH_TYPE_SET(iecho,ICMP_ECHO);
113   ICMPH_CODE_SET(iecho, 0);
114   iecho->chksum = 0;
115   iecho->id     = PING_ID;
116   iecho->seqno  = htons(++ping_seq_num);
117   iecho->chksum = inet_chksum(iecho, len);
118
119   /* fill the additional data buffer with some data */
120   for(i = 0; i < PING_DATA_SIZE; i++) {
121     ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = i;
122   }
123 }
124
125 #if LWIP_SOCKET
126
127 /* Ping using the socket ip */
128 static err_t
129 ping_send(int s, struct ip_addr *addr)
130 {
131   int err;
132   struct icmp_echo_hdr *iecho;
133   struct sockaddr_in to;
134   size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
135
136   if (!(iecho = mem_malloc(ping_size))) {
137     return ERR_MEM;
138   }
139
140   ping_prepare_echo(iecho, ping_size);
141
142   to.sin_len = sizeof(to);
143   to.sin_family = AF_INET;
144   to.sin_addr.s_addr = addr->addr;
145
146   err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
147
148   mem_free(iecho);
149
150   return (err ? ERR_OK : ERR_VAL);
151 }
152
153 static void
154 ping_recv(int s)
155 {
156   char buf[64];
157   int fromlen, len;
158   struct sockaddr_in from;
159   struct ip_hdr *iphdr;
160   struct icmp_echo_hdr *iecho;
161
162   while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) {
163     if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) {
164       LWIP_DEBUGF( PING_DEBUG, ("ping: recv "));
165       ip_addr_debug_print(PING_DEBUG, (struct ip_addr *)&(from.sin_addr));
166       LWIP_DEBUGF( PING_DEBUG, (" %lu ms\n", (sys_now()-ping_time)));
167
168       iphdr = (struct ip_hdr *)buf;
169       iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
170       if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
171         /* do some ping result processing */
172         PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER));
173         return;
174       } else {
175         LWIP_DEBUGF( PING_DEBUG, ("ping: drop\n"));
176       }
177     }
178   }
179
180   if (len == 0) {
181     LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %lu ms - timeout\n", (sys_now()-ping_time)));
182   }
183
184   /* do some ping result processing */
185   PING_RESULT(0);
186 }
187
188 static void
189 ping_thread(void *arg)
190 {
191   int s;
192   int timeout = PING_RCV_TIMEO;
193   struct ip_addr ping_target;
194
195   LWIP_UNUSED_ARG(arg);
196
197   if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) {
198     return;
199   }
200
201   lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
202
203   while (1) {
204     ping_target = PING_TARGET;
205
206     if (ping_send(s, &ping_target) == ERR_OK) {
207       LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
208       ip_addr_debug_print(PING_DEBUG, &ping_target);
209       LWIP_DEBUGF( PING_DEBUG, ("\n"));
210
211       ping_time = sys_now();
212       ping_recv(s);
213     } else {
214       LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
215       ip_addr_debug_print(PING_DEBUG, &ping_target);
216       LWIP_DEBUGF( PING_DEBUG, (" - error\n"));
217     }
218     sys_msleep(PING_DELAY);
219   }
220 }
221
222 #else /* LWIP_SOCKET */
223
224 /* Ping using the raw ip */
225 static u8_t
226 ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *addr)
227 {
228   struct icmp_echo_hdr *iecho;
229
230   if (pbuf_header( p, -PBUF_IP_HLEN)==0) {
231     iecho = p->payload;
232
233     if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
234       LWIP_DEBUGF( PING_DEBUG, ("ping: recv "));
235       ip_addr_debug_print(PING_DEBUG, addr);
236       LWIP_DEBUGF( PING_DEBUG, (" %lu ms\n", (sys_now()-ping_time)));
237
238       /* do some ping result processing */
239       PING_RESULT(1);
240     }
241   }
242
243   return 1; /* eat the event */
244 }
245
246 static void
247 ping_send(struct raw_pcb *raw, struct ip_addr *addr)
248 {
249   struct pbuf *p;
250   struct icmp_echo_hdr *iecho;
251   size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
252
253   if (!(p = pbuf_alloc(PBUF_IP, ping_size, PBUF_RAM))) {
254     return;
255   }
256   if ((p->len == p->tot_len) && (p->next == NULL)) {
257     iecho = p->payload;
258
259     ping_prepare_echo(iecho, ping_size);
260
261     raw_sendto(raw, p, addr);
262     ping_time = sys_now();
263   }
264   pbuf_free(p);
265 }
266
267 static void
268 ping_timeout(void *arg)
269 {
270   struct raw_pcb *pcb = (struct raw_pcb*)arg;
271   struct ip_addr ping_target = PING_TARGET;
272   
273   LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL);
274
275   LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
276   ip_addr_debug_print(PING_DEBUG, &ping_target);
277   LWIP_DEBUGF( PING_DEBUG, ("\n"));
278
279   ping_send(pcb, &ping_target);
280
281   sys_timeout(PING_DELAY, ping_timeout, pcb);
282 }
283
284 static void
285 ping_raw_init(void)
286 {
287   struct raw_pcb *pcb;
288
289   if (!(pcb = raw_new(IP_PROTO_ICMP))) {
290     return;
291   }
292
293   raw_recv(pcb, ping_recv, NULL);
294   raw_bind(pcb, IP_ADDR_ANY);
295   sys_timeout(PING_DELAY, ping_timeout, pcb);
296 }
297
298 #endif /* LWIP_SOCKET */
299
300 void
301 ping_init(void)
302 {
303 #if LWIP_SOCKET
304   sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
305 #else /* LWIP_SOCKET */
306   ping_raw_init();
307 #endif /* LWIP_SOCKET */
308 }
309
310
311 u32_t
312 sys_now()
313 {
314   ulong_t msec;
315
316   msec = clock_time();
317     
318   return msec;
319 }
320
321 #endif /* LWIP_RAW && LWIP_ICMP */