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, DYNAMIC_ND);
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];
213 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
214 dst_ipv6[i] = ipv6_h->dst_addr[i];
216 multi_addr = dst_ipv6[0];
218 /* Check for Multicast Address */
219 if ((IPV6_MULTICAST & ((multi_addr << 8) | dst_ipv6[1]))
220 || !memcmp(&port->macaddr[0], ð_h->d_addr, 6)) {
222 populate_nd_entry(src_hw_addr, src_ipv6, port->pmdid,
225 /* build a Neighbor Advertisement message */
226 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
227 req_tipv6[i] = icmpv6_nd_h->target_ipv6[i];
231 &((ipv6list_t *) port->ipv6_list)->ipaddr[0],
234 ether_addr_copy(ð_h->s_addr, ð_h->d_addr);
235 ether_addr_copy((struct ether_addr *)&port->
236 macaddr[0], ð_h->s_addr);
238 /* set sender mac address */
239 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
240 ipv6_h->dst_addr[i] =
242 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
243 ipv6_h->src_addr[i] = req_tipv6[i];
244 icmpv6_h->icmpv6_type =
245 ICMPV6_NEIGHBOR_ADVERTISEMENT;
246 icmpv6_nd_h->type = e_Target_Link_Layer_Address;
247 icmpv6_nd_h->length = 1;
248 memcpy(&icmpv6_nd_h->link_layer_addr[0],
249 &port->macaddr[0], 6);
250 icmpv6_nd_h->icmpv6_reserved = 0;
251 icmpv6_nd_h->icmpv6_reserved |=
253 (NEIGHBOR_ROUTER_OVERRIDE_SET);
255 icmpv6_h->icmpv6_cksum = 0;
256 icmpv6_h->icmpv6_cksum =
257 ~icmpv6_ipv6_nd_checksum(pkt);
259 port->transmit_bulk_pkts(port, &pkt, 1);
261 } else if (ARPICMP_DEBUG) {
263 ("............Some one else is the target host here !!!\n");
270 ("...............Malformed ND Solicitation message!!!\n");
274 } else if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_ADVERTISEMENT)
275 && (icmpv6_h->icmpv6_code == 0)) {
276 struct ether_addr *src_hw_addr = ð_h->s_addr;
278 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) {
279 ipv6[i] = ipv6_h->src_addr[i];
282 populate_nd_entry(src_hw_addr, ipv6, port->pmdid, DYNAMIC_ND);
285 printf("ICMPv6 Type %d Not Supported yet !!!\n",
286 icmpv6_h->icmpv6_type);
290 rte_pktmbuf_free(pkt);
293 struct rte_mbuf *request_icmpv6_echo(uint8_t ipv6[], l2_phy_interface_t *port)
295 struct ether_hdr *eth_h;
296 struct ipv6_hdr *ipv6_h;
297 struct icmpv6_hdr *icmpv6_h;
298 struct icmpv6_info_hdr *icmpv6_info_h;
302 struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt;
303 if (icmpv6_pkt == NULL) {
305 printf("Error allocating icmpv6_pkt rte_mbuf\n");
309 eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *);
311 ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
313 (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
315 (struct icmpv6_info_hdr *)((char *)icmpv6_h +
316 sizeof(struct icmpv6_hdr));
318 ether_addr_copy((struct ether_addr *)&port->macaddr[0], ð_h->s_addr);
319 eth_h->ether_type = rte_bswap16(0x86dd);
320 for (i = 0; i < 6; i++) {
321 eth_h->d_addr.addr_bytes[i] = 0;
324 ipv6_h->vtc_flow = rte_bswap32(0x60000000);
325 ipv6_h->payload_len = rte_bswap16(64);
327 ipv6_h->hop_limits = 64;
329 for (i = 0; i < 16; i++) {
330 ipv6_h->src_addr[i] = 0x0;
331 ipv6_h->dst_addr[i] = ipv6[i];
334 icmpv6_h->icmpv6_type = ICMPV6_ECHO_REQUEST;
335 icmpv6_h->icmpv6_code = 0;
336 icmpv6_info_h->icmpv6_ident = rte_bswap16(0x5151);
337 icmpv6_info_h->icmpv6_seq_nb = rte_bswap16(0x1);
339 icmp_data = (uint8_t *) icmpv6_h + 8;
340 for (i = 0; i < 56; i++) {
344 icmpv6_h->icmpv6_cksum = 0;
345 icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_echo_checksum(icmpv6_pkt);
347 icmpv6_pkt->pkt_len =
348 sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 64;
349 icmpv6_pkt->data_len = icmpv6_pkt->pkt_len;
352 port->transmit_single_pkt(port, icmpv6_pkt);
357 struct rte_mbuf *request_nd(uint8_t ipv6[], l2_phy_interface_t *port)
359 struct ether_hdr *eth_h;
360 struct ipv6_hdr *ipv6_h;
361 struct icmpv6_hdr *icmpv6_h;
362 struct icmpv6_nd_hdr *icmpv6_nd_h;
365 struct rte_mbuf *icmpv6_pkt = lib_nd_pkt[port->pmdid];
366 if (icmpv6_pkt == NULL) {
368 printf("Error allocating icmpv6_pkt rte_mbuf\n");
372 uint8_t dst_ip[] = {255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 16, 100, 20};
373 uint8_t dst_mac[] = {51,51,255, 16, 100, 20};
375 eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *);
377 ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr));
379 (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr));
381 (struct icmpv6_nd_hdr *)((char *)icmpv6_h +
382 sizeof(struct icmpv6_hdr));
384 ether_addr_copy((struct ether_addr *)&port->macaddr[0], ð_h->s_addr);
385 eth_h->ether_type = rte_bswap16(0x86dd);
387 for (i = 0; i < 6; i++) {
389 eth_h->d_addr.addr_bytes[i] = dst_mac[i];
391 eth_h->d_addr.addr_bytes[i] = ipv6[i];
394 for (i=13; i<16; i++)
397 uint8_t *addr = ((ipv6list_t *) (port->ipv6_list))->ipaddr;
399 ipv6_h->vtc_flow = rte_bswap32(0x60000000);
400 ipv6_h->payload_len = rte_bswap16(32);
402 ipv6_h->hop_limits = 255;
404 for (i = 0; i < 16; i++) {
405 ipv6_h->src_addr[i] = *(addr + i);
406 ipv6_h->dst_addr[i] = dst_ip[i];
409 icmpv6_h->icmpv6_type = ICMPV6_NEIGHBOR_SOLICITATION;
410 icmpv6_h->icmpv6_code = 0;
412 icmpv6_nd_h->icmpv6_reserved = 0x0;
413 icmpv6_nd_h->icmpv6_reserved |=
415 (NEIGHBOR_ROUTER_OVERRIDE_SET);
417 for (i = 0; i < ND_IPV6_ADDR_SIZE; i++)
418 icmpv6_nd_h->target_ipv6[i] = ipv6[i];
419 icmpv6_nd_h->type = e_Source_Link_Layer_Address;
420 icmpv6_nd_h->length = 1;
421 memcpy(&icmpv6_nd_h->link_layer_addr[0], &port->macaddr[0], 6);
423 icmpv6_h->icmpv6_cksum = 0;
424 icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_nd_checksum(icmpv6_pkt);
425 icmpv6_pkt->pkt_len =
426 sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 32;
427 icmpv6_pkt->data_len = icmpv6_pkt->pkt_len;
430 port->transmit_single_pkt(port, icmpv6_pkt);