2 // Copyright (c) 2017 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
16 /* Santosh Sethupathi*/
18 #include "lib_icmpv6.h"
20 static void print_pkt(uint8_t *rd)
24 printf("Packet Contents:\n");
26 for (i = 0; i < 20; i++) {
27 for (j = 0; j < 20; j++)
28 printf("%02x ", rd[(20 * i) + j]);
34 static uint16_t icmpv6_ipv6_nd_checksum(struct rte_mbuf *pkt)
36 struct ether_hdr *eth_h;
37 struct ipv6_hdr *ipv6_h;
38 struct icmpv6_hdr *icmpv6_h;
40 size_t tmplen, offset;
41 uint8_t *tmppacket, *tpacket;
43 eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
44 ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
46 (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
48 uint32_t payloadlen = 0x20;
49 payloadlen = rte_bswap32(payloadlen);
51 tmplen = 40 + sizeof(struct icmpv6_hdr) + sizeof(struct icmpv6_nd_hdr);
52 tmplen = RTE_CACHE_LINE_ROUNDUP(tmplen);
53 tmppacket = rte_zmalloc(NULL, tmplen, RTE_CACHE_LINE_SIZE);
57 memcpy(tpacket, &ipv6_h->src_addr[0], offset);
59 memcpy(tpacket, &ipv6_h->dst_addr[0], offset);
67 memcpy(tpacket, &ipv6_h->proto, 1);
69 memcpy(tpacket, &payloadlen, 4);
71 memcpy(tpacket, icmpv6_h,
72 sizeof(struct icmpv6_hdr) + sizeof(struct icmpv6_nd_hdr));
77 return rte_raw_cksum(tmppacket, tmplen);
80 static uint16_t icmpv6_ipv6_echo_checksum(struct rte_mbuf *pkt)
82 struct ether_hdr *eth_h;
83 struct ipv6_hdr *ipv6_h;
84 struct icmpv6_hdr *icmpv6_h;
86 size_t tmplen, offset;
87 uint8_t *tmppacket, *tpacket;
89 eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
90 ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
92 (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
94 uint32_t payloadlen = rte_bswap16(ipv6_h->payload_len);
95 uint32_t payloadlen_swap = rte_bswap32(payloadlen);
98 printf("%s: payloadlen: %u\n", __FUNCTION__, payloadlen);
100 tmplen = 40 + payloadlen;
101 tmplen = RTE_CACHE_LINE_ROUNDUP(tmplen);
102 tmppacket = rte_zmalloc(NULL, tmplen, RTE_CACHE_LINE_SIZE);
106 memcpy(tpacket, &ipv6_h->src_addr[0], offset);
108 memcpy(tpacket, &ipv6_h->dst_addr[0], offset);
116 memcpy(tpacket, &ipv6_h->proto, 1);
118 memcpy(tpacket, &payloadlen_swap, 4);
120 memcpy(tpacket, icmpv6_h, payloadlen);
123 print_pkt(tmppacket);
125 return rte_raw_cksum(tmppacket, tmplen);
128 void process_icmpv6_pkt(struct rte_mbuf *pkt, l2_phy_interface_t *port)
131 struct ether_hdr *eth_h;
132 struct ipv6_hdr *ipv6_h;
133 struct icmpv6_hdr *icmpv6_h;
134 struct icmpv6_nd_hdr *icmpv6_nd_h;
135 uint8_t ipv6_addr[16];
137 uint8_t req_tipv6[16];
138 /* To drop the packet */
141 printf("port is NULL");
143 } else if (port->ipv6_list == NULL) {
144 printf("IPV6 address not configured on link\n");
148 eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
149 ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
151 (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
153 if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REQUEST)
154 && (icmpv6_h->icmpv6_code == 0)) {
155 for (i = 0; i < 16; i++) {
156 ipv6_addr[i] = ipv6_h->src_addr[i];
159 ether_addr_copy(ð_h->s_addr, ð_h->d_addr);
160 ether_addr_copy((struct ether_addr *)&port->macaddr[0],
163 for (i = 0; i < 16; i++)
164 ipv6_h->src_addr[i] = ipv6_h->dst_addr[i];
165 for (i = 0; i < 16; i++)
166 ipv6_h->dst_addr[i] = ipv6_addr[i];
168 icmpv6_h->icmpv6_type = ICMPV6_ECHO_REPLY;
169 icmpv6_h->icmpv6_cksum = 0;
170 icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_echo_checksum(pkt);
171 port->transmit_bulk_pkts(port, &pkt, 1);
174 } else if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REPLY)
175 && (icmpv6_h->icmpv6_code == 0)) {
176 struct nd_key_ipv6 nd_key;
177 nd_key.port_id = port->pmdid;
178 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
179 nd_key.ipv6[i] = ipv6_h->src_addr[i];
186 /*Validate if key-value pair already exists in the hash table for ND IPv6 */
187 struct nd_entry_data *new_nd_data = retrieve_nd_entry(nd_key);
188 if (new_nd_data == NULL) {
190 ("Received unsolicited ICMPv6 echo reply on port %d\n",
192 for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) {
193 printf("%02X%02X ", nd_key.ipv6[i],
199 new_nd_data->status = COMPLETE;
200 } else if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_SOLICITATION)
201 && (icmpv6_h->icmpv6_code == 0)) {
204 (struct icmpv6_nd_hdr *)((char *)icmpv6_h +
205 sizeof(struct icmpv6_hdr));
206 struct ether_addr *src_hw_addr = ð_h->s_addr;
207 uint8_t src_ipv6[16], dst_ipv6[16];
210 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
211 src_ipv6[i] = ipv6_h->src_addr[i];
212 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
213 dst_ipv6[i] = ipv6_h->dst_addr[i];
215 multi_addr = dst_ipv6[0];
217 /* Check for Multicast Address */
218 if ((IPV6_MULTICAST & ((multi_addr << 8) | dst_ipv6[1]))
219 || !memcmp(&port->macaddr[0], ð_h->d_addr, 6)) {
220 populate_nd_entry(src_hw_addr, src_ipv6, port->pmdid,
223 /* build a Neighbor Advertisement message */
224 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
225 req_tipv6[i] = icmpv6_nd_h->target_ipv6[i];
229 &((ipv6list_t *) port->ipv6_list)->ipaddr[0],
232 ether_addr_copy(ð_h->s_addr, ð_h->d_addr);
233 ether_addr_copy((struct ether_addr *)&port->
234 macaddr[0], ð_h->s_addr);
236 /* set sender mac address */
237 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
238 ipv6_h->dst_addr[i] =
240 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
241 ipv6_h->src_addr[i] = req_tipv6[i];
242 icmpv6_h->icmpv6_type =
243 ICMPV6_NEIGHBOR_ADVERTISEMENT;
244 icmpv6_nd_h->type = e_Target_Link_Layer_Address;
245 icmpv6_nd_h->length = 1;
246 memcpy(&icmpv6_nd_h->link_layer_addr[0],
247 &port->macaddr[0], 6);
248 icmpv6_nd_h->icmpv6_reserved = 0;
249 icmpv6_nd_h->icmpv6_reserved |=
251 (NEIGHBOR_ROUTER_OVERRIDE_SET);
253 icmpv6_h->icmpv6_cksum = 0;
254 icmpv6_h->icmpv6_cksum =
255 ~icmpv6_ipv6_nd_checksum(pkt);
257 port->transmit_bulk_pkts(port, &pkt, 1);
259 } else if (ARPICMP_DEBUG) {
261 ("............Some one else is the target host here !!!\n");
268 ("...............Malformed ND Solicitation message!!!\n");
272 } else if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_ADVERTISEMENT)
273 && (icmpv6_h->icmpv6_code == 0)) {
274 struct ether_addr *src_hw_addr = ð_h->s_addr;
276 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
277 ipv6[i] = ipv6_h->src_addr[i];
280 populate_nd_entry(src_hw_addr, ipv6, port->pmdid, DYNAMIC_ND);
283 printf("ICMPv6 Type %d Not Supported yet !!!\n",
284 icmpv6_h->icmpv6_type);
288 rte_pktmbuf_free(pkt);
291 struct rte_mbuf *request_icmpv6_echo(uint8_t ipv6[], l2_phy_interface_t *port)
293 struct ether_hdr *eth_h;
294 struct ipv6_hdr *ipv6_h;
295 struct icmpv6_hdr *icmpv6_h;
296 struct icmpv6_info_hdr *icmpv6_info_h;
300 struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt;
301 if (icmpv6_pkt == NULL) {
303 printf("Error allocating icmpv6_pkt rte_mbuf\n");
307 eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *);
309 ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
311 (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
313 (struct icmpv6_info_hdr *)((char *)icmpv6_h +
314 sizeof(struct icmpv6_hdr));
316 ether_addr_copy((struct ether_addr *)&port->macaddr[0], ð_h->s_addr);
317 eth_h->ether_type = rte_bswap16(0x86dd);
318 for (i = 0; i < 6; i++) {
319 eth_h->d_addr.addr_bytes[i] = 0;
322 ipv6_h->vtc_flow = rte_bswap32(0x60000000);
323 ipv6_h->payload_len = rte_bswap16(64);
325 ipv6_h->hop_limits = 64;
327 for (i = 0; i < 16; i++) {
328 ipv6_h->src_addr[i] = 0x0;
329 ipv6_h->dst_addr[i] = ipv6[i];
332 icmpv6_h->icmpv6_type = ICMPV6_ECHO_REQUEST;
333 icmpv6_h->icmpv6_code = 0;
334 icmpv6_info_h->icmpv6_ident = rte_bswap16(0x5151);
335 icmpv6_info_h->icmpv6_seq_nb = rte_bswap16(0x1);
337 icmp_data = (uint8_t *) icmpv6_h + 8;
338 for (i = 0; i < 56; i++) {
342 icmpv6_h->icmpv6_cksum = 0;
343 icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_echo_checksum(icmpv6_pkt);
345 icmpv6_pkt->pkt_len =
346 sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 64;
347 icmpv6_pkt->data_len = icmpv6_pkt->pkt_len;
352 struct rte_mbuf *request_nd(uint8_t ipv6[], l2_phy_interface_t *port)
354 struct ether_hdr *eth_h;
355 struct ipv6_hdr *ipv6_h;
356 struct icmpv6_hdr *icmpv6_h;
357 struct icmpv6_nd_hdr *icmpv6_nd_h;
360 struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt;
361 if (icmpv6_pkt == NULL) {
363 printf("Error allocating icmpv6_pkt rte_mbuf\n");
367 eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *);
369 ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
371 (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
373 (struct icmpv6_nd_hdr *)((char *)icmpv6_h +
374 sizeof(struct icmpv6_hdr));
376 ether_addr_copy((struct ether_addr *)&port->macaddr[0], ð_h->s_addr);
377 eth_h->ether_type = rte_bswap16(0x86dd);
378 for (i = 0; i < 6; i++) {
379 eth_h->d_addr.addr_bytes[i] = 0;
382 ipv6_h->vtc_flow = 0x60000000;
383 ipv6_h->payload_len = rte_bswap16(32);
385 ipv6_h->hop_limits = 64;
387 for (i = 0; i < 16; i++) {
388 ipv6_h->src_addr[i] = 0x0;
389 ipv6_h->dst_addr[i] = ipv6[i];
392 icmpv6_h->icmpv6_type = ICMPV6_NEIGHBOR_SOLICITATION;
393 icmpv6_h->icmpv6_code = 0;
395 icmpv6_nd_h->icmpv6_reserved = 0x0;
396 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
397 icmpv6_nd_h->target_ipv6[i] = ipv6[i];
398 icmpv6_nd_h->type = e_Source_Link_Layer_Address;
399 icmpv6_nd_h->length = 1;
400 memcpy(&icmpv6_nd_h->link_layer_addr[0], &port->macaddr[0], 6);
402 icmpv6_h->icmpv6_cksum = 0;
403 icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_nd_checksum(icmpv6_pkt);
405 icmpv6_pkt->pkt_len =
406 sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 32;
407 icmpv6_pkt->data_len = icmpv6_pkt->pkt_len;