Contiki 3.x
shell-ping.c
1 /*
2  * Copyright (c) 2004, Adam Dunkels.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * Author: Adam Dunkels <adam@sics.se>
32  *
33  */
34 
35 #include <string.h>
36 #include <stddef.h>
37 
38 #include "contiki.h"
39 #include "shell.h"
40 #include "contiki-net.h"
41 
42 /*---------------------------------------------------------------------------*/
43 PROCESS(shell_ping_process, "ping");
44 SHELL_COMMAND(ping_command,
45  "ping",
46  "ping <host>: ping an IP host",
47  &shell_ping_process);
48 /*---------------------------------------------------------------------------*/
49 
50 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
51 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN])
52 #define PING_DATALEN 16
53 
54 #define ICMP_ECHO_REPLY 0
55 #define ICMP_ECHO 8
56 
57 #define ICMP6_ECHO_REPLY 129
58 #define ICMP6_ECHO 128
59 
60 static uip_ipaddr_t remoteaddr;
61 static unsigned char running;
62 /*---------------------------------------------------------------------------*/
63 static void
64 send_ping(uip_ipaddr_t *dest_addr)
65 #if UIP_CONF_IPV6
66 {
67  static uint16_t count;
68  UIP_IP_BUF->vtc = 0x60;
69  UIP_IP_BUF->tcflow = 1;
70  UIP_IP_BUF->flow = 0;
71  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
72  UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit;
73  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest_addr);
74  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
75 
77  UIP_ICMP_BUF->icode = 0;
78  /* set identifier and sequence number to 0 */
79  memset((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, 0, 4);
80  /* put one byte of data */
81  memset((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN + UIP_ICMP6_ECHO_REQUEST_LEN,
82  count, PING_DATALEN);
83  count++;
84 
85  uip_len = UIP_ICMPH_LEN + UIP_ICMP6_ECHO_REQUEST_LEN +
86  UIP_IPH_LEN + PING_DATALEN;
87  UIP_IP_BUF->len[0] = (uint8_t)((uip_len - 40) >> 8);
88  UIP_IP_BUF->len[1] = (uint8_t)((uip_len - 40) & 0x00ff);
89 
90  UIP_ICMP_BUF->icmpchksum = 0;
91  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
92 
94 }
95 #else /* UIP_CONF_IPV6 */
96 {
97  static uint16_t ipid = 0;
98  static uint16_t seqno = 0;
99 
100  UIP_IP_BUF->vhl = 0x45;
101  UIP_IP_BUF->tos = 0;
102  UIP_IP_BUF->ipoffset[0] = UIP_IP_BUF->ipoffset[1] = 0;
103  ++ipid;
104  UIP_IP_BUF->ipid[0] = ipid >> 8;
105  UIP_IP_BUF->ipid[1] = ipid & 0xff;
106  UIP_IP_BUF->proto = UIP_PROTO_ICMP;
107  UIP_IP_BUF->ttl = UIP_TTL;
108 
109  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest_addr);
110  uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &uip_hostaddr);
111 
112  UIP_ICMP_BUF->type = ICMP_ECHO;
113  UIP_ICMP_BUF->icode = 0;
114  UIP_ICMP_BUF->id = 0xadad;
115  UIP_ICMP_BUF->seqno = uip_htons(seqno++);
116 
117  uip_len = UIP_ICMPH_LEN + UIP_IPH_LEN + PING_DATALEN;
118  UIP_IP_BUF->len[0] = (uint8_t)((uip_len) >> 8);
119  UIP_IP_BUF->len[1] = (uint8_t)((uip_len) & 0x00ff);
120 
121  UIP_ICMP_BUF->icmpchksum = 0;
122  UIP_ICMP_BUF->icmpchksum = ~uip_chksum((uint16_t *)&(UIP_ICMP_BUF->type),
123  UIP_ICMPH_LEN + PING_DATALEN);
124 
125  /* Calculate IP checksum. */
126  UIP_IP_BUF->ipchksum = 0;
127  UIP_IP_BUF->ipchksum = ~(uip_ipchksum());
128 
129  tcpip_output();
130 }
131 #endif /* UIP_CONF_IPV6 */
132 /*---------------------------------------------------------------------------*/
133 PROCESS_THREAD(shell_ping_process, ev, data)
134 {
135  static struct etimer e;
136  struct shell_input *input;
137 
138  PROCESS_BEGIN();
139 
140  if(data == NULL) {
141  shell_output_str(&ping_command,
142  "ping <server>: server as address", "");
143  PROCESS_EXIT();
144  }
145  uiplib_ipaddrconv(data, &remoteaddr);
146 
147  send_ping(&remoteaddr);
148 
149  running = 1;
150 
151  while(running) {
152  etimer_set(&e, CLOCK_SECOND * 10);
153 
155 
156  if(etimer_expired(&e)) {
157  PROCESS_EXIT();
158  }
159 
160  if(ev == shell_event_input) {
161  input = data;
162  if(input->len1 + input->len2 == 0) {
163  PROCESS_EXIT();
164  }
165 #if 0
166  } else if(ev == resolv_event_found) {
167  /* Either found a hostname, or not. */
168  if((char *)data != NULL &&
169  resolv_lookup((char *)data, &ipaddr) == RESOLV_STATUS_CACHED) {
170  uip_ipaddr_copy(serveraddr, ipaddr);
171  telnet_connect(&s, server, serveraddr, nick);
172  } else {
173  shell_output_str(&ping_command, "Host not found.", "");
174  }
175 #endif /* 0 */
176  }
177  }
178 
179  PROCESS_END();
180 }
181 /*---------------------------------------------------------------------------*/
182 void
183 shell_ping_init(void)
184 {
185  shell_register_command(&ping_command);
186 }
187 /*---------------------------------------------------------------------------*/
uint16_t uip_ipchksum(void)
Calculate the IP header checksum of the packet header in uip_buf.
Definition: uip6.c:343
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:205
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
Definition: tcpip.c:540
Hostname is fresh and usable.
Definition: resolv.h:68
void shell_output_str(struct shell_command *c, char *text1, const char *text2)
Output strings from a shell command.
Definition: shell.c:383
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
uint16_t uip_chksum(uint16_t *buf, uint16_t len)
Calculate the Internet checksum over a buffer.
Definition: uip6.c:336
Main header file for the Contiki shell
#define NULL
The null pointer.
uint8_t tcpip_output(const uip_lladdr_t *a)
Output packet to layer 2 The eventual parameter is the MAC address of the destination.
Definition: tcpip.c:115
#define uiplib_ipaddrconv
Convert a textual representation of an IP address to a numerical representation.
Definition: uiplib.h:71
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:104
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
uint16_t uip_icmp6chksum(void)
Calculate the ICMP checksum of the packet in uip_buf.
Definition: uip6.c:387
CCIF process_event_t resolv_event_found
Event that is broadcasted when a DNS name has been resolved.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
Structure for shell input data.
Definition: shell.h:365
CCIF uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
Definition: uip6.c:2298
void shell_register_command(struct shell_command *c)
Register a command with the shell.
Definition: shell.c:413
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define ICMP6_ECHO_REQUEST
Echo request.
Definition: uip-icmp6.h:57
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
Definition: uip-ds6.c:497
#define UIP_ICMP_BUF
Pointer to ICMP header.
Definition: uip-nd6.c:105
int shell_event_input
The event number for shell input data.
Definition: shell.c:70
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
#define UIP_TTL
The IP TTL (time to live) of IP packets sent by uIP.
Definition: uipopt.h:245
A timer.
Definition: etimer.h:76
#define UIP_ICMP6_ECHO_REQUEST_LEN
Echo Request constant part length.
Definition: uip-icmp6.h:99
#define SHELL_COMMAND(name, command, description, process)
Define a shell command.
Definition: shell.h:219
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82