xref: /mOS-networking-stack/core/src/icmp.c (revision cc3c5712)
1 #include <stdint.h>
2 #include <sys/types.h>
3 #include <netinet/ip.h>
4 #include <string.h>
5 
6 #include "mtcp.h"
7 #include "icmp.h"
8 #include "eth_out.h"
9 #include "ip_in.h"
10 #include "ip_out.h"
11 #include "debug.h"
12 #include "arp.h"
13 #include "timer.h"
14 #include "config.h"
15 
16 #define IP_NEXT_PTR(iph) ((uint8_t *)iph + (iph->ihl << 2))
17 void
18 DumpICMPPacket(struct icmphdr *icmph, uint32_t saddr, uint32_t daddr);
19 
20 /*----------------------------------------------------------------------------*/
21 
22 /*
23 struct icmphdr
24 {
25     uint8_t icmp_type;
26     uint8_t icmp_code;
27     uint16_t icmp_checksum;
28     uint16_t icmp_id;
29     uint16_t icmp_sequence;
30 };
31 */
32 
33 /*----------------------------------------------------------------------------*/
34 static uint16_t
35 ICMPChecksum(uint16_t *icmph, int len)
36 {
37     assert(len >= 0);
38 
39     uint16_t ret = 0;
40     uint32_t sum = 0;
41     uint16_t odd_byte;
42 
43     while (len > 1) {
44         sum += *icmph++;
45         len -= 2;
46     }
47 
48     if (len == 1) {
49         *(uint8_t*)(&odd_byte) = * (uint8_t*)icmph;
50         sum += odd_byte;
51     }
52 
53     sum =  (sum >> 16) + (sum & 0xffff);
54     sum += (sum >> 16);
55     ret =  ~sum;
56 
57     return ret;
58 }
59 /*----------------------------------------------------------------------------*/
60 static uint8_t*
61 ICMPOutput(struct mtcp_manager *mtcp, struct pkt_ctx *pctx, uint32_t saddr, uint32_t daddr,
62         uint8_t icmp_type, uint8_t icmp_code, uint16_t icmp_id, uint16_t icmp_seq,
63         uint8_t *icmpd, uint16_t len)
64 {
65     struct iphdr *iph;
66     int32_t nif;
67     uint8_t *haddr;
68     struct icmphdr *icmph;
69     uint32_t pktlen = sizeof(struct iphdr) + sizeof(struct icmphdr) + len;
70     struct timeval cur_ts = {0};
71     uint32_t ts;
72 
73     /* Get hardware interface to forward the packet*/
74     nif = GetOutputInterface(daddr);
75     if (nif < 0)
76         return (uint8_t *) ERROR;
77 
78     /* Get next hop MAC address */
79     haddr = GetDestinationHWaddr(daddr);
80     if (!haddr) {
81         uint8_t *da = (uint8_t *)&daddr;
82         TRACE_INFO("[WARNING] The destination IP %u.%u.%u.%u "
83                    "is not in ARP table!\n",
84                    da[0], da[1], da[2], da[3]);
85 	/* ARP requests will not be created if it's a standalone middlebox */
86 	if (!pctx->forward)
87 		RequestARP(mtcp, daddr, nif, mtcp->cur_ts);
88         haddr = GetDestinationHWaddr(daddr);
89     }
90 
91     /* Check if we have valid next hop address */
92     if (!haddr)
93 	    return (uint8_t *) ERROR;
94 
95     /* Set up timestamp for EthernetOutput */
96     gettimeofday(&cur_ts, NULL);
97     ts = TIMEVAL_TO_TS(&cur_ts);
98 
99     /* Allocate a buffer */
100     iph = (struct iphdr *)EthernetOutput(mtcp, pctx, ETH_P_IP, nif, haddr, pktlen, ts);
101     if (!iph)
102 	    return (uint8_t *) ERROR;
103 
104     /* Fill in the ip header */
105     iph->ihl = IP_HEADER_LEN >> 2;
106     iph->version = 4;
107     iph->tos = 0;
108     iph->tot_len = htons(pktlen);
109     iph->id = htons(0);
110     iph->frag_off = htons(IP_DF);
111     iph->ttl = 64;
112     iph->protocol = IPPROTO_ICMP;
113     iph->saddr = saddr;
114     iph->daddr = daddr;
115     iph->check = 0;
116     iph->check = ip_fast_csum(iph, iph->ihl);
117 
118     icmph = (struct icmphdr *) IP_NEXT_PTR(iph);
119 
120     /* Fill in the icmp header */
121     icmph->icmp_type = icmp_type;
122     icmph->icmp_code = icmp_code;
123     icmph->icmp_checksum = 0;
124     ICMP_ECHO_SET_ID(icmph, htons(icmp_id));
125     ICMP_ECHO_SET_SEQ(icmph, htons(icmp_seq));
126 
127     /* Fill in the icmp data */
128     if(len > 0)
129         memcpy((void *) (icmph + 1), icmpd, len);
130 
131     /* Calculate ICMP Checksum with header and data */
132     icmph->icmp_checksum =
133                        ICMPChecksum((uint16_t *)icmph, sizeof(struct icmphdr) + len);
134 
135 #if DBGMSG
136     DumpICMPPacket(icmph, saddr, daddr);
137 #endif
138     return (uint8_t *)(iph + 1);
139 }
140 /*----------------------------------------------------------------------------*/
141 void
142 RequestICMP(mtcp_manager_t mtcp, struct pkt_ctx *pctx, uint32_t saddr, uint32_t daddr,
143         uint16_t icmp_id, uint16_t icmp_sequence,
144         uint8_t *icmpd, uint16_t len)
145 {
146     /* send icmp request with given parameters */
147     ICMPOutput(mtcp, pctx, saddr, daddr, ICMP_ECHO, 0, ntohs(icmp_id), ntohs(icmp_sequence),
148                icmpd, len);
149 }
150 /*----------------------------------------------------------------------------*/
151 static int
152 ProcessICMPECHORequest(mtcp_manager_t mtcp, struct pkt_ctx *pctx, struct icmphdr *icmph)
153 {
154     int ret = 0;
155 
156     /* Check correctness of ICMP checksum and send ICMP echo reply */
157     if (ICMPChecksum((uint16_t *) icmph, pctx->p.ip_len - (pctx->p.iph->ihl << 2) ))
158         ret = ERROR;
159     else
160         ICMPOutput(mtcp, pctx, pctx->p.iph->daddr, pctx->p.iph->saddr, ICMP_ECHOREPLY, 0,
161                    ntohs(ICMP_ECHO_GET_ID(icmph)), ntohs(ICMP_ECHO_GET_SEQ(icmph)), (uint8_t *) (icmph + 1),
162                    (uint16_t) (pctx->p.ip_len - (pctx->p.iph->ihl << 2) - sizeof(struct icmphdr)) );
163 
164     return ret;
165 }
166 /*----------------------------------------------------------------------------*/
167 static int
168 ProcessICMPECHOReply(mtcp_manager_t mtcp, struct pkt_ctx *pctx, struct icmphdr *icmph)
169 {
170 
171     /* XXX We can allow sending ping request from mOS app. IMHO, it's bad */
172 
173 #if 0
174     uint8_t type, code;
175     uint16_t seq, id;
176 
177     /* Extract ICMP field from packet */
178     type = icmph->icmp_type;
179     code = icmph->icmp_code;
180     seq  = ntohs(ICMP_ECHO_GET_SEQ(icmph));
181     id   = ntohs(ICMP_ECHO_GET_ID(icmph));
182 #endif
183     return 0;
184 }
185 /*----------------------------------------------------------------------------*/
186 int
187 ProcessICMPPacket(mtcp_manager_t mtcp, struct pkt_ctx *pctx)
188 {
189     struct icmphdr *icmph = (struct icmphdr *) IP_NEXT_PTR(pctx->p.iph);
190     int i;
191     int to_me = FALSE;
192 
193     /* process the icmp messages destined to me */
194     for (i = 0; i < g_config.mos->netdev_table->num; i++) {
195         if (pctx->p.iph->daddr == g_config.mos->netdev_table->ent[i]->ip_addr) {
196             to_me = TRUE;
197         }
198     }
199 
200     if (!to_me)
201         return FALSE;
202 
203     switch (icmph->icmp_type)
204     {
205         case ICMP_ECHO:
206             ProcessICMPECHORequest(mtcp, pctx, icmph);
207             break;
208 
209         case ICMP_ECHOREPLY:
210             ProcessICMPECHOReply(mtcp, pctx, icmph);
211             break;
212 
213         case ICMP_DEST_UNREACH:
214             TRACE_INFO("[INFO] ICMP Destination Unreachable message received\n");
215             break;
216 
217         case ICMP_TIME_EXCEEDED:
218             TRACE_INFO("[INFO] ICMP Time Exceeded message received\n");
219             break;
220 
221         default:
222             TRACE_INFO("[INFO] Unsupported ICMP message type %x received\n",
223                        icmph->icmp_type);
224             break;
225     }
226 
227     return TRUE;
228 }
229 /*----------------------------------------------------------------------------*/
230 void
231 DumpICMPPacket(struct icmphdr *icmph, uint32_t saddr, uint32_t daddr)
232 {
233     uint8_t *t;
234 
235     fprintf(stderr, "ICMP header: \n");
236     fprintf(stderr, "Type: %d, "
237             "Code: %d, ID: %d, Sequence: %d\n",
238             icmph->icmp_type, icmph->icmp_code,
239             ICMP_ECHO_GET_ID(icmph), ICMP_ECHO_GET_SEQ(icmph));
240 
241     t = (uint8_t *)&saddr;
242     fprintf(stderr, "Sender IP: %u.%u.%u.%u\n",
243             t[0], t[1], t[2], t[3]);
244 
245     t = (uint8_t *)&daddr;
246     fprintf(stderr, "Target IP: %u.%u.%u.%u\n",
247             t[0], t[1], t[2], t[3]);
248 }
249 /*----------------------------------------------------------------------------*/
250 #undef IP_NEXT_PTR
251