/* // Copyright (c) 2017 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #include #include "cgnapt_pcp_be.h" #include "pipeline_cgnapt_be.h" #include "pipeline_cgnapt_common.h" /** * @file * Pipeline CG-NAPT PCP BE Implementation. * * Implementation of Pipeline CG-NAPT PCP Back End (BE). * Handles PCP requests for both IPv4 & IPv6 * Constructs PCP responses for both IPv4 & IPv6 * Provides backend CLI support. * Runs on CGNAPT pipeline core * * */ #ifdef PCP_ENABLE uint32_t pcp_lifetime = 60; uint8_t pcp_ipv4_format[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }; /** * Function to initialize PCP stuff * */ enum PCP_RET pcp_init(void) { /* Init of PCP mempool */ if (!pcp_pool_init) { pcp_pool_init = 1; pcp_mbuf_pool = rte_pktmbuf_pool_create( "pcp_mbuf_pool", 64, 32, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); if (pcp_mbuf_pool == NULL) { printf("PCP mbuf pool creation failed\n"); return PCP_INIT_UNSUCCESS; } } printf("In pcp_init: success\n"); return PCP_INIT_SUCCESS; } /** * Function to handle PCP CLI commands * * @param p * Pipieline struct associated with each pipeline * @param msg * CLI message enqueued by master thread */ void *pipeline_cgnapt_msg_req_pcp_handler( __rte_unused struct pipeline *p, void *msg) { struct pipeline_cgnapt_pcp_msg_rsp *rsp = msg; struct pipeline_cgnapt_pcp_msg_req *req = msg; req = msg; rsp->status = 0; if (req->cmd == CGNAPT_PCP_CMD_STATS) { printf("pcp_success_count:%d\n", pcp_success_count); printf("pcp_error_count:%d\n", pcp_error_count); printf("pcp_entry_count:%d\n", pcp_entry_count); return rsp; } if (req->cmd == CGNAPT_PCP_CMD_PCP_ENABLE) { if (req->lifetime) { pcp_enable = 1; printf("PCP option is enabled\n"); } else{ pcp_enable = 0; printf("PCP option is disabled\n"); } return rsp; } if (req->cmd == CGNAPT_PCP_CMD_SET_LIFETIME) { pcp_lifetime = req->lifetime; printf("pcp_lifetime:%" PRIu32 "\n", pcp_lifetime); return rsp; } if (req->cmd == CGNAPT_PCP_CMD_GET_LIFETIME) { printf("pcp_lifetime:%" PRIu32 "\n", pcp_lifetime); return rsp; } printf("CG-NAPT PCP handler called with wrong args %x %x\n", req->cmd, req->lifetime); printf("\n"); return rsp; } void clone_data( struct rte_mbuf *rx_pkt, struct rte_mbuf *tx_pkt); /** * Function to copy Rx pkt data to Tx pkt data * * @param rx_pkt * Received PCP pkt * @param tx_pkt * Transmitting PCP pkt */ void clone_data( struct rte_mbuf *rx_pkt, struct rte_mbuf *tx_pkt) { char *buf1; char *buf2; buf1 = rte_pktmbuf_mtod(rx_pkt, char *); buf2 = rte_pktmbuf_append(tx_pkt, rx_pkt->data_len); rte_memcpy(buf2, buf1, rx_pkt->data_len); } /** * Function to construct L2,L3,L4 in pkt and to send out * * @param rx_pkt * Received PCP pkt * @param tx_pkt * Transmitting PCP pkt * @param ver * Version of pkt : IPv4 or IPv6 * @param p_nat * A pointer to struct rte_pipeline */ void construct_pcp_resp( struct rte_mbuf *rx_pkt, struct rte_mbuf *tx_pkt, uint8_t ver, struct rte_pipeline *rte_p) { struct ether_hdr *eth_tx, *eth_rx; struct ipv4_hdr *ipv4_tx, *ipv4_rx; struct ipv6_hdr *ipv6_tx, *ipv6_rx; struct udp_hdr *udp_tx, *udp_rx; struct pcp_resp_hdr *pcp_resp; struct pcp_req_hdr *pcp_req; tx_pkt->port = rx_pkt->port; if (ver == 4) { pcp_req = (struct pcp_req_hdr *) ((uint8_t *) rx_pkt + IPV4_PCP_OFST); pcp_resp = (struct pcp_resp_hdr *) ((uint8_t *) tx_pkt + IPV4_PCP_OFST); } else { pcp_req = (struct pcp_req_hdr *) ((uint8_t *) rx_pkt + IPV6_PCP_OFST); pcp_resp = (struct pcp_resp_hdr *) ((uint8_t *) tx_pkt + IPV6_PCP_OFST); } if (pcp_resp->result_code == PCP_SUCCESS) { memset(pcp_resp->reserve, 0, 12); pcp_success_count++; } else { memcpy(pcp_resp->reserve, &pcp_req->cli_ip[1], 12); pcp_error_count++; } pcp_resp->req_resp = PCP_RESP; pcp_resp->res_unuse = 0x00; /* Epoch time */ pcp_resp->epoch_time = rte_bswap32(time(NULL)); /* swap L2 identities */ eth_rx = rte_pktmbuf_mtod(rx_pkt, struct ether_hdr *); eth_tx = rte_pktmbuf_mtod(tx_pkt, struct ether_hdr *); memcpy(ð_tx->s_addr, ð_rx->d_addr, sizeof(struct ether_addr)); memcpy(ð_tx->d_addr, ð_rx->s_addr, sizeof(struct ether_addr)); /* swap L3 identities */ if (ver == 4) { ipv4_rx = (struct ipv4_hdr *)((uint8_t *) rx_pkt + IP_OFFSET); udp_rx = (struct udp_hdr *)((uint8_t *) rx_pkt + IPV4_UDP_OFST); ipv4_tx = (struct ipv4_hdr *)((uint8_t *) tx_pkt + IP_OFFSET); udp_tx = (struct udp_hdr *)((uint8_t *) tx_pkt + IPV4_UDP_OFST); ipv4_tx->src_addr = ipv4_rx->dst_addr; ipv4_tx->dst_addr = ipv4_rx->src_addr; /* swap L4 identities */ udp_tx->src_port = udp_rx->dst_port; udp_tx->dst_port = udp_rx->src_port; udp_tx->dgram_cksum = 0; udp_tx->dgram_cksum = rte_ipv4_udptcp_cksum(ipv4_tx, (void *)udp_tx); ipv4_tx->total_length = rte_cpu_to_be_16(pcp_resp->result_code == PCP_MAP ? IPV4_PCP_MAP_PL_LEN : IPV4_PCP_PEER_PL_LEN); ipv4_tx->packet_id = 0xaabb; ipv4_tx->fragment_offset = 0x0000; ipv4_tx->time_to_live = 64; ipv4_tx->next_proto_id = IP_PROTOCOL_UDP; ipv4_tx->hdr_checksum = 0; ipv4_tx->hdr_checksum = rte_ipv4_cksum(ipv4_tx); } else { ipv6_rx = (struct ipv6_hdr *)((uint8_t *) rx_pkt + IP_OFFSET); udp_rx = (struct udp_hdr *)((uint8_t *) rx_pkt + IPV6_UDP_OFST); ipv6_tx = (struct ipv6_hdr *)((uint8_t *) tx_pkt + IP_OFFSET); udp_tx = (struct udp_hdr *)((uint8_t *) tx_pkt + IPV6_UDP_OFST); memcpy((uint8_t *)&ipv6_tx->src_addr[0], (uint8_t *)&ipv6_rx->dst_addr[0], 16); memcpy((uint8_t *)&ipv6_tx->dst_addr[0], (uint8_t *)&ipv6_rx->src_addr[0], 16); /* swap L4 identities */ udp_tx->src_port = udp_rx->dst_port; udp_tx->dst_port = udp_rx->src_port; udp_tx->dgram_cksum = 0; udp_tx->dgram_cksum = rte_ipv6_udptcp_cksum(ipv6_tx, (void *)udp_tx); ipv6_tx->payload_len = rte_cpu_to_be_16(pcp_resp->result_code == PCP_MAP ? IPV6_PCP_MAP_PL_LEN : IPV6_PCP_PEER_PL_LEN); ipv6_tx->proto = IP_PROTOCOL_UDP; ipv6_tx->hop_limits = 64; } #ifdef PCP_DEBUG rte_hexdump(stdout, "Transferring PCP Pkt", tx_pkt, 400); #endif rte_pipeline_port_out_packet_insert(rte_p, tx_pkt->port, tx_pkt); } /** * Function to handle PCP requests * * @param rx_pkt * Received PCP pkt * @param ver * Version of pkt : IPv4 or IPv6 * @param p_nat * A pointer to struct pipeline_cgnapt */ void handle_pcp_req(struct rte_mbuf *rx_pkt, uint8_t ver, void *pipeline_cgnapt_ptr) { struct ipv4_hdr *ipv4 = NULL; struct ipv6_hdr *ipv6 = NULL; struct udp_hdr *udp_rx = NULL; struct pcp_req_hdr *pcp_req = NULL; struct pcp_resp_hdr *pcp_resp = NULL; struct rte_mbuf *tx_pkt = NULL; struct pipeline_cgnapt *p_nat = pipeline_cgnapt_ptr; if (pcp_mbuf_pool == NULL) printf("handle PCP: PCP pool is NULL\n"); tx_pkt = rte_pktmbuf_alloc(pcp_mbuf_pool); if (tx_pkt == NULL) { printf("unable to allocate mem from PCP pool\n"); return; } /* clone the pkt */ clone_data(rx_pkt, tx_pkt); #ifdef PCP_DEBUG rte_hexdump(stdout, "cloned PCP Pkt", tx_pkt, 400); #endif if (ver == 4) { pcp_req = (struct pcp_req_hdr *) ((uint8_t *) rx_pkt + IPV4_PCP_OFST); pcp_resp = (struct pcp_resp_hdr *) ((uint8_t *) tx_pkt + IPV4_PCP_OFST); udp_rx = (struct udp_hdr *) ((uint8_t *) rx_pkt + IPV4_UDP_OFST); } else { pcp_req = (struct pcp_req_hdr *) ((uint8_t *) rx_pkt + IPV6_PCP_OFST); pcp_resp = (struct pcp_resp_hdr *) ((uint8_t *) tx_pkt + IPV6_PCP_OFST); udp_rx = (struct udp_hdr *) ((uint8_t *) rx_pkt + IPV6_UDP_OFST); } /* Check for all conditions to drop the packet */ /* Check the PCP version */ if (pcp_req->ver != 2) { #ifdef PCP_DEBUG printf("PCP version mismatch\n"); #endif pcp_resp->result_code = PCP_UNSUPP_VERSION; pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } /* If req msg is less than 2 octects */ if (rte_bswap16(udp_rx->dgram_len) > 1100) { #ifdef PCP_DEBUG printf("PCP len > 1000\n"); #endif pcp_resp->result_code = PCP_MALFORMED_REQUEST; pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } /* Silently drop the response pkt */ if (pcp_req->req_resp == PCP_RESP) { #ifdef PCP_DEBUG printf("Its PCP Resp\n"); #endif return; } /* Check for supported PCP opcode */ if ((pcp_req->opcode != PCP_MAP) && (pcp_req->opcode != PCP_PEER)) { #ifdef PCP_DEBUG printf("Neither PCP_MAP not PCP_PEER\n"); #endif pcp_resp->result_code = PCP_UNSUPP_OPCODE; printf("result code:%d\n", PCP_UNSUPP_OPCODE); pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } /* To check whether options are using in PCP */ { uint8_t *option = (uint8_t *) ((uint8_t *) udp_rx + PCP_REQ_RESP_HDR_SZ + PCP_MAP_REQ_RESP_SZ); if (*option) { #ifdef PCP_DEBUG printf("No PCP option support\n"); #endif pcp_resp->result_code = PCP_UNSUPP_OPTION; pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } } if (ver == 4) { ipv4 = (struct ipv4_hdr *)((uint8_t *) rx_pkt + IP_OFFSET); /* Check whether 3rd party host is requesting */ if (ipv4->src_addr != pcp_req->cli_ip[3]) { #ifdef PCP_DEBUG printf("PCP client IP & req IP mismatch\n"); #endif printf("src addr:%x req addr:%x\n", ipv4->src_addr, pcp_req->cli_ip[3]); pcp_resp->result_code = PCP_ADDRESS_MISMATCH; pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } } else { ipv6 = (struct ipv6_hdr *)((uint8_t *) rx_pkt + IP_OFFSET); /* 5. Check whether 3rd party host is requesting */ if (memcmp(ipv6->src_addr, pcp_req->cli_ip, IPV6_SZ) != 0) { #ifdef PCP_DEBUG printf("PCP client IP & req IP mismatch\n"); #endif pcp_resp->result_code = PCP_ADDRESS_MISMATCH; pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } } struct pipeline_cgnapt_entry_key key; memset(&key, 0, sizeof(struct pipeline_cgnapt_entry_key)); int pos = 0; switch (pcp_req->opcode) { case PCP_MAP: { struct pcp_map_req *map_req; struct pcp_map_resp *map_resp; /* Not a PCP MAP Request(36) */ if ((rte_be_to_cpu_16(udp_rx->dgram_len) - sizeof(struct pcp_req_hdr)) <= 35) return; if (ver == 4) { map_req = (struct pcp_map_req *) ((uint8_t *) rx_pkt + IPV4_PCP_MAP_OFST); map_resp = (struct pcp_map_resp *) ((uint8_t *) tx_pkt + IPV4_PCP_MAP_OFST); } else { map_req = (struct pcp_map_req *) ((uint8_t *) rx_pkt + IPV6_PCP_MAP_OFST); map_resp = (struct pcp_map_resp *) ((uint8_t *) tx_pkt + IPV6_PCP_MAP_OFST); } /* 4. Check for supported protocol */ if (map_req->protocol != IP_PROTOCOL_TCP && map_req->protocol != IP_PROTOCOL_UDP) { #ifdef PCP_DEBUG printf("PCP Req is neither TCP nor " "UDP protocol\n"); #endif pcp_resp->result_code = PCP_UNSUPP_PROTOCOL; pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } /* Preparing key to search the entry */ key.pid = rx_pkt->port; key.ip = rte_bswap32(pcp_req->cli_ip[3]); key.port = rte_bswap16(map_req->int_port); #ifdef NAT_ONLY_CONFIG_REQ if (nat_only_config_flag) key.port = 0xffff; #endif #ifdef PCP_DEBUG rte_hexdump(stdout, "key", &key, sizeof(struct pipeline_cgnapt_entry_key)); #endif pos = rte_hash_lookup(napt_common_table, &key); /* PCP request for deleting the CGNAPT entry */ if (rte_bswap32(pcp_req->life_time) == 0) { if (pos != -ENOENT) { long long int time_out; time_out = napt_hash_tbl_entries[pos]. data.timeout; /* Check for PCP entry first */ if (time_out > 0) { rte_hash_del_key (napt_common_table, &key); pcp_resp->life_time = 0; pcp_resp->result_code = PCP_SUCCESS; memset(pcp_resp->reserve, 0, 12); #ifdef PCP_DEBUG printf("PCP SUCCESS : PCP MAP req for " "deleting entry\n"); #endif construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } if (time_out == STATIC_CGNAPT_TIMEOUT) pcp_resp->life_time = 0xffffffff; else if (time_out == DYNAMIC_CGNAPT_TIMEOUT) pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); pcp_resp->result_code = PCP_NOT_AUTHORIZED; #ifdef PCP_DEBUG printf("PCP Failed : Not a PCP request " "created entry\n"); #endif construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } else { pcp_resp->life_time = 0; pcp_resp->result_code = PCP_SUCCESS; memset(pcp_resp->reserve, 0, 12); #ifdef PCP_DEBUG printf("PCP SUCCESS : MAP req entry not " "found for deletion\n"); #endif construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } } /* PCP request for adding the CGNAPT entry */ struct cgnapt_table_entry *entry = NULL; if ((pos == -ENOENT)) { uint8_t err = 0; entry = add_dynamic_cgnapt_entry(&p_nat->p, &key, rte_bswap32(pcp_req->life_time) <= pcp_lifetime? rte_bswap32(pcp_req->life_time): pcp_lifetime, ver == 4 ? CGNAPT_ENTRY_IPV4 : CGNAPT_ENTRY_IPV6, ipv6->src_addr, &err); /* Ignore klocwork issue in above calling */ /* MAP Err : unable to allocate * requested resources */ if (!entry) { #ifdef PCP_DEBUG printf("PCP Failure : unable to " "create PCP req entry\n"); #endif pcp_resp->result_code = PCP_NO_RESOURCES; pcp_resp->life_time = rte_bswap32(PCP_SHORT_LTIME); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } #ifdef PCP_DEBUG printf("PCP dynamic entry created " "successfully\n"); #endif pcp_entry_count++; } else { /* Check whether PCP request created * entry or not */ if (napt_hash_tbl_entries[pos].data. timeout > 0) { napt_hash_tbl_entries[pos]. data.timeout = pcp_lifetime; struct cgnapt_table_entry *p_entry, *s_entry; struct pipeline_cgnapt_entry_key s_key; p_entry = &napt_hash_tbl_entries[pos]; entry = &napt_hash_tbl_entries[pos]; s_key.port = napt_hash_tbl_entries[pos]. data.pub_port; s_key.ip = napt_hash_tbl_entries[pos]. data.pub_ip; s_key.pid = napt_hash_tbl_entries[pos]. data.pub_phy_port; /* Getting ingress or second entry * from the table */ pos = rte_hash_lookup(napt_common_table, &s_key); s_entry = &napt_hash_tbl_entries[pos]; /* Enqueue the info to * restart the timer */ timer_thread_enqueue(&key, &s_key, p_entry, s_entry, (struct pipeline *)p_nat); } else { // if dynamic if (!napt_hash_tbl_entries[pos]. data.timeout) pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); else // if static entry pcp_resp->life_time = 0xffffffff; pcp_resp->result_code = PCP_NOT_AUTHORIZED; #ifdef PCP_DEBUG printf("PCP Failure : Not authorized " "to delete entry\n"); printf("Not a PCP request " "created entry\n"); #endif construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } } /* Fill PCP Resp fields */ pcp_resp->result_code = PCP_SUCCESS; rte_bswap32(pcp_req->life_time) < pcp_lifetime? (pcp_resp->life_time = pcp_req->life_time): (pcp_resp->life_time = rte_bswap32(pcp_lifetime)); /* Fill PCP MAP Resp fields */ memcpy(map_resp->nonce, map_req->nonce, 12); map_resp->protocol = map_req->protocol; map_resp->res_unuse1 = 0; map_resp->int_port = map_req->int_port; /* Ignore klockwork issue for below stmt */ map_resp->ext_port = rte_be_to_cpu_16(entry->data.pub_port); memcpy(map_resp->ext_ip, pcp_ipv4_format, 12); map_resp->ext_ip[3] = rte_bswap32(entry->data.pub_ip); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } break; case PCP_PEER: { /* Not a PCP PEER Request(56) */ if ((rte_be_to_cpu_16(udp_rx->dgram_len) - sizeof(struct pcp_req_hdr)) <= 55) return; struct cgnapt_table_entry *p_entry, *s_entry; struct pipeline_cgnapt_entry_key s_key; struct pcp_peer_req *peer_req; struct pcp_peer_resp *peer_resp; peer_req = (struct pcp_peer_req *)((uint8_t *) rx_pkt + IPV4_PCP_PEER_OFST); peer_resp = (struct pcp_peer_resp *)((uint8_t *) rx_pkt + IPV4_PCP_PEER_OFST); /* PEER Err : Creation not supporting */ if (pcp_req->life_time == 0) { pcp_resp->life_time = 0; pcp_resp->result_code = PCP_MALFORMED_REQUEST; #ifdef PCP_DEBUG printf("PCP Failure : PEER creation not " "supported\n"); #endif construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } /* Preparing key to search the entry */ key.pid = rx_pkt->port; /* For both IPv4 & IPv6, key is last 32 bits * due to NAT64 */ key.ip = rte_bswap32(pcp_req->cli_ip[3]); key.port = rte_bswap16(peer_req->int_port); #ifdef NAT_ONLY_CONFIG_REQ if (nat_only_config_flag) key.port = 0xffff; #endif /* PEER Err : If no requested entry is found */ pos = rte_hash_lookup(napt_common_table, &key); if (pos == -ENOENT) { pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); pcp_resp->result_code = PCP_MALFORMED_REQUEST; #ifdef PCP_DEBUG printf("PCP Failure : unable to find entry\n"); #endif construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } /* If requested created entry */ if (napt_hash_tbl_entries[pos].data. timeout > 0) { napt_hash_tbl_entries[pos]. data.timeout = pcp_lifetime; p_entry = &napt_hash_tbl_entries[pos]; s_key.port = napt_hash_tbl_entries[pos]. data.pub_port; s_key.ip = napt_hash_tbl_entries[pos]. data.pub_ip; s_key.pid = napt_hash_tbl_entries[pos]. data.pub_phy_port; /* Getting ingress or second entry * from the table */ pos = rte_hash_lookup(napt_common_table, &s_key); s_entry = &napt_hash_tbl_entries[pos]; /* Enqueue the info to restart the timer */ timer_thread_enqueue(&key, &s_key, p_entry, s_entry, (struct pipeline *)p_nat); } else{ // dynamic entry if (!napt_hash_tbl_entries[pos].data.timeout) pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME); else // if static entry pcp_resp->life_time = 0xffffffff; pcp_resp->result_code = PCP_NOT_AUTHORIZED; #ifdef PCP_DEBUG printf("PCP Failure : Not a PCP request " "created entry\n"); #endif construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } /* PEER Success */ /* Fill PCP Response */ rte_bswap16(pcp_req->life_time) < pcp_lifetime? (pcp_resp->life_time = pcp_req->life_time): (pcp_resp->life_time = rte_bswap32(pcp_lifetime)); pcp_resp->result_code = PCP_SUCCESS; /* Fill PCP PEER Resonse */ memcpy(peer_resp->nonce, peer_req->nonce, 12); peer_resp->protocol = peer_req->protocol; peer_resp->res_unuse1 = 0; peer_resp->int_port = rte_be_to_cpu_16(peer_req->int_port); peer_resp->ext_port = rte_be_to_cpu_16(peer_req->ext_port); memcpy(peer_resp->ext_ip, peer_req->ext_ip, 16); memcpy(peer_resp->ext_ip, pcp_ipv4_format, 12); peer_resp->ext_ip[3] = rte_bswap32(p_entry->data.pub_ip); peer_resp->rpeer_port = rte_be_to_cpu_16(peer_req->rpeer_port); peer_resp->res_unuse2 = 0x0000; memcpy(peer_resp->rpeer_ip, peer_req->rpeer_ip, 16); construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p); return; } default: printf("This never hits\n"); } } #endif