From f0bfb2b0c8467154990b49beafb991b7515e37e3 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Mon, 17 Apr 2017 23:03:43 -0700 Subject: vCGNAPT VNF initial check-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JIRA: SAMPLEVNF-5 The vCGNAPT implementation contains following features: • Static and dynamic Network address translation. • Static and dynamic Network address and port translation • ARP (request, response, gratuitous) • ICMP (terminal echo, echo response, pass-through) • ICMPv6 and ND • UDP, TCP and ICMP protocol pass-through • Multithread support and Multiple physical port support • Limiting max ports per client • Limiting max clients per public IP address • Live Session tracking to NAT flow • NAT64 – connectivity between IPv6 access network to IPv4 data • PCP - Port Control protocol • SIP functionality • FTP functionality Change-Id: I5ebb44ae60e32dd6da5e793efd91a6831a4d30a7 Signed-off-by: Deepak S --- VNFs/vCGNAPT/pipeline/cgnapt_pcp_be.c | 825 ++++++++++++++++++++++++++++++++++ 1 file changed, 825 insertions(+) create mode 100644 VNFs/vCGNAPT/pipeline/cgnapt_pcp_be.c (limited to 'VNFs/vCGNAPT/pipeline/cgnapt_pcp_be.c') diff --git a/VNFs/vCGNAPT/pipeline/cgnapt_pcp_be.c b/VNFs/vCGNAPT/pipeline/cgnapt_pcp_be.c new file mode 100644 index 00000000..e91fd75b --- /dev/null +++ b/VNFs/vCGNAPT/pipeline/cgnapt_pcp_be.c @@ -0,0 +1,825 @@ +/* +// 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 -- cgit 1.2.3-korg