FD.io VPP  v17.10-9-gd594711
Vector Packet Processing
icmp_proto.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17 
18 #include <stdint.h>
19 #include <net/if.h>
20 #include <sys/types.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <sys/uio.h>
26 #include <sys/mman.h>
27 #include <sys/prctl.h>
28 #include <inttypes.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <netdb.h>
32 #include <linux/ip.h>
33 #include <linux/icmp.h>
34 #include <arpa/inet.h>
35 #include <stdlib.h>
36 #include <netinet/if_ether.h>
37 #include <net/if_arp.h>
38 #include <asm/byteorder.h>
39 #include <byteswap.h>
40 
41 #include <icmp_proto.h>
42 
43 static uint16_t
44 cksum (void *addr, ssize_t len)
45 {
46  char *data = (char *) addr;
47 
48  uint32_t acc = 0xffff;
49 
50  ssize_t i;
51  for (i = 0; (i + 1) < len; i += 2)
52  {
53  uint16_t word;
54  memcpy (&word, data + i, 2);
55  acc += ntohs (word);
56  if (acc > 0xffff)
57  acc -= 0xffff;
58  }
59 
60  if (len & 1)
61  {
62  uint16_t word = 0;
63  memcpy (&word, data + len - 1, 1);
64  acc += ntohs (word);
65  if (acc > 0xffff)
66  acc -= 0xffff;
67  }
68  return htons (~acc);
69 }
70 
71 int
72 print_packet (void *pck)
73 {
74  if (pck == NULL)
75  {
76  printf ("ICMP_PROTO: no data\n");
77  return -1;
78  }
79  struct iphdr *ip;
80  struct icmphdr *icmp;
81  ip = (struct iphdr *) pck;
82  icmp = (struct icmphdr *) (pck + sizeof (struct iphdr));
83  printf ("received packet:\n");
84  printf ("\tiphdr:\n");
85  printf ("\t\tihl: %u\n\t\tversion: %u\n\t\tlen: %u\n\t\tid: %u\n",
86  ip->ihl, ip->version, __bswap_16 (ip->tot_len), ip->id);
87  printf ("\t\tprotocol: %u\n", ip->protocol);
88 
89  printf ("\t\tsaddr: ");
90  int i;
91  for (i = 0; i < 4; i++)
92  {
93  printf ("%u.", ((uint8_t *) & ip->saddr)[i]);
94  }
95  printf ("\n");
96 
97  printf ("\t\tdaddr: ");
98  for (i = 0; i < 4; i++)
99  {
100  printf ("%u.", ((uint8_t *) & ip->daddr)[i]);
101  }
102  printf ("\n");
103  printf ("\ticmphdr:\n");
104  printf ("\t\ttype: %s\n",
105  (icmp->type == ICMP_ECHO) ? "ICMP_ECHO" : "ICMP_ECHOREPLY");
106 
107  return 0;
108 }
109 
110 static ssize_t
111 resolve_arp (void *arp)
112 {
113  struct arphdr *resp = (struct arphdr *) arp;
114 
115  resp->ar_hrd = __bswap_16 (ARPHRD_ETHER);
116 
117  resp->ar_pro = __bswap_16 (0x0800);
118 
119  resp->ar_hln = 6;
120  resp->ar_pln = 4;
121 
122  resp->ar_op = __bswap_16 (ARPOP_REPLY);
123 
124  return sizeof (struct arphdr);
125 }
126 
127 static ssize_t
128 resolve_eth_arp (struct ether_arp *eth_arp, void *eth_arp_resp,
129  uint8_t ip_addr[4])
130 {
131  struct ether_arp *resp = (struct ether_arp *) eth_arp_resp;
132 
133  resolve_arp (&resp->ea_hdr);
134 
135  memcpy (resp->arp_tha, eth_arp->arp_sha, 6);
136  memcpy (resp->arp_tpa, eth_arp->arp_spa, 4);
137 
138  memcpy (resp->arp_sha,
139  (((struct ether_header *) (eth_arp_resp -
140  sizeof (struct ether_header)))->
141  ether_shost), 6);
142 
143  memcpy (resp->arp_spa, ip_addr, 4);
144 
145  return sizeof (struct ether_arp);
146 }
147 
148 static ssize_t
149 resolve_eth (struct ether_header *eth, void *eth_resp)
150 {
151  struct ether_header *resp = (struct ether_header *) eth_resp;
152  memcpy (resp->ether_dhost, eth->ether_shost, 6);
153 
154  uint8_t hw_addr[6];
155  int i;
156  for (i = 0; i < 6; i++)
157  {
158  hw_addr[i] = 'a';
159  }
160  memcpy (resp->ether_shost, hw_addr, 6);
161 
162  resp->ether_type = eth->ether_type;
163 
164  return sizeof (struct ether_header);
165 }
166 
167 static ssize_t
168 resolve_ip (struct iphdr *ip, void *ip_resp, uint8_t ip_addr[4])
169 {
170  struct iphdr *resp = (struct iphdr *) ip_resp;
171  resp->ihl = 5;
172  resp->version = 4;
173  resp->tos = 0;
174  /*len updated later */
175  resp->tot_len = 0x5400;
176  resp->id = 0;
177  resp->frag_off = 0;
178  resp->ttl = 0x40;
179  resp->protocol = 1;
180  ((uint8_t *) & resp->saddr)[0] = ip_addr[0];
181  ((uint8_t *) & resp->saddr)[1] = ip_addr[1];
182  ((uint8_t *) & resp->saddr)[2] = ip_addr[2];
183  ((uint8_t *) & resp->saddr)[3] = ip_addr[3];
184  resp->daddr = ip->saddr;
185 
186  resp->check = cksum (resp, sizeof (struct iphdr));
187 
188  return sizeof (struct iphdr);
189 }
190 
191 static ssize_t
192 resolve_icmp (struct icmphdr *icmp, void *icmp_resp)
193 {
194  struct icmphdr *resp = (struct icmphdr *) icmp_resp;
195  resp->type = ICMP_ECHOREPLY;
196  resp->code = 0;
197  resp->un.echo.id = icmp->un.echo.id;
198  resp->un.echo.sequence = icmp->un.echo.sequence;
199 
200  /*resp->checksum = cksum (resp, sizeof (struct icmphdr)); */
201 
202  return sizeof (struct icmphdr);
203 }
204 
205 int
206 resolve_packet (void *in_pck, ssize_t in_size,
207  void *out_pck, uint32_t * out_size, uint8_t ip_addr[4])
208 {
209  struct ether_header *eh;
210  struct ether_arp *eah;
211  struct iphdr *ip;
212  struct icmphdr *icmp;
213  *out_size = 0;
214 
215  eh = (struct ether_header *) in_pck;
216  *out_size = resolve_eth (eh, out_pck);
217 
218  if (eh->ether_type == 0x0608)
219  {
220  eah = (struct ether_arp *) (in_pck + *out_size);
221  *out_size += resolve_eth_arp (eah, out_pck + *out_size, ip_addr);
222 
223  }
224  else if (eh->ether_type == 0x0008)
225  {
226 #ifdef ICMP_DBG
227  print_packet (in_pck + *out_size);
228 #endif
229  ip = (struct iphdr *) (in_pck + *out_size);
230  *out_size += resolve_ip (ip, out_pck + *out_size, ip_addr);
231  if (ip->protocol == 1)
232  {
233  icmp = (struct icmphdr *) (in_pck + *out_size);
234  *out_size += resolve_icmp (icmp, out_pck + *out_size);
235  ((struct icmphdr *) (out_pck + *out_size -
236  sizeof (struct icmphdr)))->checksum =
237  cksum (out_pck + *out_size - sizeof (struct icmphdr),
238  sizeof (struct icmphdr));
239  /* payload */
240  memcpy (out_pck + *out_size, in_pck + *out_size,
241  in_size - *out_size);
242  *out_size = in_size;
243  }
244  }
245  return 0;
246 }
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define NULL
Definition: clib.h:55
static ssize_t resolve_arp(void *arp)
Definition: icmp_proto.c:111
int resolve_packet(void *in_pck, ssize_t in_size, void *out_pck, uint32_t *out_size, uint8_t ip_addr[4])
Definition: icmp_proto.c:206
int print_packet(void *pck)
Definition: icmp_proto.c:72
static ssize_t resolve_eth(struct ether_header *eth, void *eth_resp)
Definition: icmp_proto.c:149
static ssize_t resolve_eth_arp(struct ether_arp *eth_arp, void *eth_arp_resp, uint8_t ip_addr[4])
Definition: icmp_proto.c:128
static ssize_t resolve_icmp(struct icmphdr *icmp, void *icmp_resp)
Definition: icmp_proto.c:192
i64 word
Definition: types.h:111
static uint16_t cksum(void *addr, ssize_t len)
Definition: icmp_proto.c:44
vhost_vring_addr_t addr
Definition: vhost-user.h:83
static ssize_t resolve_ip(struct iphdr *ip, void *ip_resp, uint8_t ip_addr[4])
Definition: icmp_proto.c:168