diff options
author | Luca Muscariello <lumuscar+fdio@cisco.com> | 2019-01-17 13:47:57 +0100 |
---|---|---|
committer | Luca Muscariello <lumuscar+fdio@cisco.com> | 2019-01-17 16:32:51 +0100 |
commit | bac3da61644515f05663789b122554dc77549286 (patch) | |
tree | 898210bc8e70371d77de7d446a26c5dd4fd1165a /lib | |
parent | d5165246787301d0f13b646fda5e8a8567aef5ac (diff) |
This is the first commit of the hicn projectv19.01
Change-Id: I6f2544ad9b9f8891c88cc4bcce3cf19bd3cc863f
Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'lib')
33 files changed, 7106 insertions, 0 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100755 index 000000000..1be5e67f9 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# 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. + +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project(Hicn C) +include(CTest) + +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" +) + +if (NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE "Release") +endif() + +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + set(LIBHICN hicn) +endif() + +set(CMAKE_VERSION_MAJOR 0) +set(CMAKE_VERSION_MINOR 1) +set(CMAKE_VERSION_PATCH 1) + +option(CMAKE_BUILD_TEST "Build unit tests" OFF) + +if (NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE "Release") +endif() + +set(CMAKE_C_FLAGS -Wall) + +if (ANDROID_API) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS} -std=c99") +endif () + +add_subdirectory (src) diff --git a/lib/README.md b/lib/README.md new file mode 100755 index 000000000..6dac988db --- /dev/null +++ b/lib/README.md @@ -0,0 +1,114 @@ +# libhicn + +## Introduction + +libhicn provides a support library coded in C designed to help developers embed +Hybrid ICN (hICN) functionalities in their applications (eg. forwarder, socket +API, etc.). Its purpose is to follow the hICN specification for which it +provides a reference implementation, abstracting the user from all internal +mechanisms, and offering an API independent of the packet format (eg. IPv4 or +IPv6). The library is designed to be portable across both desktop and +mobile platforms, and we currently aim at supporting Linux, Android, OSX and +iOS, by writing the necessary adapters to realize hICN functionality in +userspace according to the available APIs and permissions that each system +offers. + +The library consists in several layers: +- the core library (hicn.h) provides a standard hICN packet format, as well as +an API allowing manipulation of packet headers; +- an hICN helper, allowing an hICN stack to be built in userspace in a portable +way, based on TUN devices and accessible though file descriptors; +- a network layer allow the sending an receiving of hICN packets on those file +descriptors, implementing both source and destination address translation as +required by the hICN mechanisms; +- finally, a "transport" API allows the forging of dummy interest and data +packets. + +A commandline interface (hicnc) is also provided that uses the library and can +for instance be used as a test traffic generator. This interface can be run as +either a consumer, a producer, or a simple forwarder. + +## Folder content + +CMakeLists.txt CMkake global build file +doc Package documentation +README.md This file +src + base.h Base definitions for hICN implementation + CMakeLists.txt CMake library build file + common.{h,c} Harmonization layer across supported platforms + compat.{h,c} Compatibility layer for former API + error.{h,c} Error management files + header.h hICN header definitions + hicn.h Master include file + mapme.{h,c} MAP-Me : anchorless producer mobility mechanisms + name.{h,c} hICN naming conventions and name processing + IP helpers + ops.{h,c} Protocol-independent hICN operations + protocol/* Protocol headers + protocol-dependent implementations + protocol.h Common file for protocols + +## Using libhicn + +### Platforms ### + +libhicn has been tested in: + +- Ubuntu 16.04 LTS (x86_64) +- Ubuntu 18.04 LTS (x86_64) +- Debian Stable/Testing +- Red Hat Enterprise Linux 7 +- CentOS 7 +- Android 8 +- iOS 12 +- macOS 10.12 +- Windows 10 + +Other platforms and architectures may work. + +### Dependencies + +Build dependencies: + +- c11 ( clang / gcc ) +- CMake 3.4 + +Basic dependencies: None + +## Installation + +You can either use released packages, or compile libhicn from sources. + +### Release mode + +mkdir build +cd build +cmake .. +make +sudo make install + +### Debug mode + +mkdir debug +cd debug +cmake .. -DCMAKE_BUILD_TYPE=Debug +make +sudo make install + +## License + +This software is distributed under the following license: + +``` +Copyright (c) 2017-2019 Cisco and/or its affiliates. +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. +``` diff --git a/lib/doc/CMakeLists.txt b/lib/doc/CMakeLists.txt new file mode 100755 index 000000000..cf022dc52 --- /dev/null +++ b/lib/doc/CMakeLists.txt @@ -0,0 +1,23 @@ +# add a target to generate API documentation with Doxygen +find_package(Doxygen) +option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) + +if(BUILD_DOCUMENTATION) + if(NOT DOXYGEN_FOUND) + message(FATAL_ERROR "Doxygen is needed to build the documentation.") + endif() + + set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) + set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + + configure_file(${doxyfile_in} ${doxyfile} @ONLY) + + add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM) + +# FIXME MS : wrong install path + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc) +endif() diff --git a/lib/doc/Doxyfile.in b/lib/doc/Doxyfile.in new file mode 100755 index 000000000..839de9f8a --- /dev/null +++ b/lib/doc/Doxyfile.in @@ -0,0 +1,12 @@ +PROJECT_NAME = "Hybrid ICN (hICN)" +PROJECT_NUMBER = v@CMAKE_VERSION_MAJOR@.@CMAKE_VERSION_MINOR@.@CMAKE_VERSION_PATCH@ +STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ \ + @PROJECT_BINARY_DIR@ +INPUT = @doxy_main_page@ \ + @PROJECT_SOURCE_DIR@ \ + @PROJECT_BINARY_DIR@ +FILE_PATTERNS = *.md \ + *.h \ + *.cc +RECURSIVE = YES +USE_MDFILE_AS_MAINPAGE = ../README.md diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt new file mode 100755 index 000000000..0137a16c7 --- /dev/null +++ b/lib/src/CMakeLists.txt @@ -0,0 +1,81 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND LIBHICN_HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/hicn.h + ${CMAKE_CURRENT_SOURCE_DIR}/base.h + ${CMAKE_CURRENT_SOURCE_DIR}/common.h + ${CMAKE_CURRENT_SOURCE_DIR}/compat.h + ${CMAKE_CURRENT_SOURCE_DIR}/error.h + ${CMAKE_CURRENT_SOURCE_DIR}/header.h + ${CMAKE_CURRENT_SOURCE_DIR}/mapme.h + ${CMAKE_CURRENT_SOURCE_DIR}/name.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h + ${CMAKE_CURRENT_SOURCE_DIR}/ops.h +) + +list(APPEND LIBHICN_HEADER_FILES_PROTOCOL + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ah.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmp.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmprd.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv4.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv6.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/tcp.h + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/udp.h +) + +list(APPEND LIBHICN_SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/compat.c + ${CMAKE_CURRENT_SOURCE_DIR}/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/mapme.c + ${CMAKE_CURRENT_SOURCE_DIR}/name.c + ${CMAKE_CURRENT_SOURCE_DIR}/ops.c + ${CMAKE_CURRENT_SOURCE_DIR}/common.c + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ah.c + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmp.c + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv4.c + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv6.c + ${CMAKE_CURRENT_SOURCE_DIR}/protocol/tcp.c +) + +set (COMPILER_DEFINITIONS "-DWITH_MAPME -DWITH_MAPME_FIXES") + +include(BuildMacros) +build_library(${LIBHICN} + SHARED STATIC + SOURCES ${LIBHICN_SOURCE_FILES} + COMPONENT libhicn + INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. + DEFINITIONS ${COMPILER_DEFINITIONS} + INSTALL_ROOT_DIR hicn + INSTALL_HEADERS ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL} +) + +add_custom_command(TARGET hicn PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E remove_directory ${PROJECT_BINARY_DIR}/hicn +) + +add_custom_command(TARGET hicn POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/hicn/ + COMMAND ${CMAKE_COMMAND} -E copy ${LIBHICN_HEADER_FILES} ${PROJECT_BINARY_DIR}/hicn/ +) + +add_custom_command(TARGET hicn POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/hicn/protocol + COMMAND ${CMAKE_COMMAND} -E copy ${LIBHICN_HEADER_FILES_PROTOCOL} ${PROJECT_BINARY_DIR}/hicn/protocol +) + +# install(FILES ${LIBHICN_HEADER_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/hicn COMPONENT libhicn) +# install(FILES ${LIBHICN_HEADER_FILES_PROTOCOL} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/hicn/protocol COMPONENT libhicn) diff --git a/lib/src/base.h b/lib/src/base.h new file mode 100755 index 000000000..c1bd23aeb --- /dev/null +++ b/lib/src/base.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file base.h + * @brief Base hICN definitions. + */ + +#ifndef HICN_BASE_H +#define HICN_BASE_H + +#include "common.h" + +/* Default header fields */ +#define HICN_DEFAULT_TTL 254 + +typedef u32 hicn_faceid_t; +typedef u8 hicn_pathlabel_t; +typedef u32 hicn_lifetime_t; + +#define HICN_MAX_LIFETIME HICN_MAX_LIFETIME_SCALED << HICN_MAX_LIFETIME_MULTIPLIER +#define HICN_MAX_LIFETIME_SCALED 0xFFFF +#define HICN_MAX_LIFETIME_MULTIPLIER 0xF /* 4 bits */ + +/** + * @brief hICN packet format type + * + * The hICN type represents the sequence of protocols that we can find in packet + * headers. They are represented as a quartet of u8 values, correponding to + * IANA protocol assignment, and read from right to left. This is done to + * faciliate decapsulation of packet header by simple shift/mask operations. + * + * For instance, an IPv6/TCP packet will be identified as : + * [IPPROTO_NONE, IPPROTO_NONE, IPPROTO_TCP, IPPROTO_IPV6] + * + * We expect four elements to be sufficient for most uses, the max being + * currently used by an hypothetical signed MAP-Me update : + * [IPPROTO_ICMPRD, IPPROTO_AH, IPPROTO_ICMP, IPPROTO_IPV6] + */ +typedef union +{ + /** protocol layers representation */ + struct + { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + u8 l1; /**< First layer */ + u8 l2; /**< Second layer */ + u8 l3; /**< Third layer */ + u8 l4; /**< Fourth layer */ +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u8 l4; /**< Fourth layer */ + u8 l3; /**< Third layer */ + u8 l2; /**< Second layer */ + u8 l1; /**< First layer */ +#else +#error "Unsupported endianness" +#endif + }; + /** u32 representation */ + u32 as_u32; +} hicn_type_t; + +/* Common protocol layers */ +#define HICN_TYPE_IPV4_TCP (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_TCP, .l1 = IPPROTO_IP }} +#define HICN_TYPE_IPV4_ICMP (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_ICMP, .l1 = IPPROTO_IP }} +#define HICN_TYPE_IPV6_TCP (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_TCP, .l1 = IPPROTO_IPV6 }} +#define HICN_TYPE_IPV6_ICMP (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_ICMPV6, .l1 = IPPROTO_IPV6 }} + + +/** + * @brief hICN Payload type + * + * This type distinguishes several types of data packet, which can either carry + * content data, or Manifest + */ +typedef enum +{ + HPT_DATA = 0, + HPT_MANIFEST = 1, + HPT_UNSPEC = 999 +} hicn_payload_type_t; + +/** + * @brief Path label computations + * + * Path label is computed by accumulating the identifiers of successive output + * faces as a Data packet is traveling from its producer back to the consumer + * originating the Interest. + * + * NOTE: this computation is not (yet) part of the hICN specification. + */ + +#define HICN_PATH_LABEL_MASK 0xF000 /* 1000 0000 0000 0000 */ +#define HICN_PATH_LABEL_SIZE 8 + +/** + * @brief Path label update + * @param [in] current_label Current pathlabel + * @param [in] face_id The face identifier to combine into the path label + * @param [out] new_label Computed pathlabel + * + * This function updates the current_label based on the new face_id, and returns + */ +always_inline void +update_pathlabel (hicn_pathlabel_t current_label, hicn_faceid_t face_id, + hicn_pathlabel_t * new_label) +{ + hicn_pathlabel_t pl_face_id = + (hicn_pathlabel_t) ((face_id & HICN_PATH_LABEL_MASK) >> + (16 - HICN_PATH_LABEL_SIZE)); + *new_label = + ((current_label << 1) | (current_label >> (HICN_PATH_LABEL_SIZE - 1))) ^ + pl_face_id; +} + +#endif /* HICN_BASE_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/common.c b/lib/src/common.c new file mode 100755 index 000000000..4b7c4a2a7 --- /dev/null +++ b/lib/src/common.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file common.c + * @brief Implementation of common interfaces abstracting low-level platform. + * details. + */ + +#include <stdlib.h> +#include <string.h> // memset +#include <sys/types.h> // getaddrinfo +#include <sys/socket.h> // '' +#include <netdb.h> // '' +#include <stdio.h> + +#include "common.h" + + +int +get_addr_family (const char *ip_address) +{ + struct addrinfo hint, *res = NULL; + int rc; + + memset (&hint, '\0', sizeof hint); + + hint.ai_family = PF_UNSPEC; + hint.ai_flags = AI_NUMERICHOST; + + rc = getaddrinfo (ip_address, NULL, &hint, &res); + if (rc) + { + return -1; + } + rc = res->ai_family; + freeaddrinfo (res); + return rc; +} + +/* hashes */ + +u32 +cumulative_hash32 (const void *data, size_t len, u32 lastValue) +{ + // Standard FNV 32-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + const u32 fnv1a_prime = 0x01000193; + u32 hash = lastValue; + size_t i; + + const char *chardata = data; + + for (i = 0; i < len; i++) + { + hash = hash ^ chardata[i]; + hash = hash * fnv1a_prime; + } + + return hash; +} + +u32 +hash32 (const void *data, size_t len) +{ + // Standard FNV 32-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + const u32 fnv1a_offset = 0x811C9DC5; + return cumulative_hash32 (data, len, fnv1a_offset); +} + +u64 +cumulative_hash64 (const void *data, size_t len, u64 lastValue) +{ + // Standard FNV 64-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + const u64 fnv1a_prime = 0x00000100000001B3ULL; + u64 hash = lastValue; + const char *chardata = data; + size_t i; + + for (i = 0; i < len; i++) + { + hash = hash ^ chardata[i]; + hash = hash * fnv1a_prime; + } + + return hash; +} + +u64 +hash64 (const void *data, size_t len) +{ + // Standard FNV 64-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param + const u64 fnv1a_offset = 0xCBF29CE484222325ULL; + return cumulative_hash64 (data, len, fnv1a_offset); +} + +void +hicn_packet_dump (uint8_t * buffer, size_t len) +{ + int i; + unsigned char buff[17]; + unsigned char *pc = (unsigned char *) buffer; + + // Output description if given. + if (len == 0) + { + printf (" ZERO LENGTH\n"); + return; + } + + // Process every byte in the data. + for (i = 0; i < len; i++) + { + // Multiple of 16 means new line (with line offset). + + if ((i % 16) == 0) + { + // Just don't print ASCII for the zeroth line. + if (i != 0) + printf (" %s\n", buff); + + // Output the offset. + printf (" %04x ", i); + } + + // Now the hex code for the specific character. + printf (" %02x", pc[i]); + + // And store a printable ASCII character for later. + if ((pc[i] < 0x20) || (pc[i] > 0x7e)) + buff[i % 16] = '.'; + else + buff[i % 16] = pc[i]; + buff[(i % 16) + 1] = '\0'; + } + + // Pad out last line if not exactly 16 characters. + while ((i % 16) != 0) + { + printf (" "); + i++; + } + + // And print the final ASCII bit. + printf (" %s\n", buff); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/common.h b/lib/src/common.h new file mode 100755 index 000000000..9ddbdeb09 --- /dev/null +++ b/lib/src/common.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file common.c + * @brief Common interfaces abstracting low-level platform. + * details. + * + * The role of this header file is to provide an uniform interface to the + * different platform on top of which we build the hICN interface: + * - syntax helpers + * - IP address management + * - protocol definition + * - ... + * + * The rationale is to leverage as much as possible platform-specific code, + * however some level of harmonization is needed to build code on top. Whenever + * possible, we align to VPP structure and naming. + */ + +#ifndef HICN_COMMON_H +#define HICN_COMMON_H + +#include <stdint.h> +#include <assert.h> + +/* Concise type definitions */ + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +/* + * Code annotations + * + * NOTE: these are defined by default in VPP. + */ + +#ifndef HICN_VPP_PLUGIN + +#define PREDICT_FALSE(x) (x) +#define PREDICT_TRUE(x) (x) +#define always_inline static inline +#define static_always_inline static inline +#define STRUCT_SIZE_OF(type, member) sizeof(((type *)0)->member) +#define ASSERT + +#define STATIC_ASSERT(x) + +#endif /* ! HICN_VPP_PLUGIN */ + +/* + * IP address types + */ + +#ifdef HICN_VPP_PLUGIN + +#include <vnet/ip/ip4_packet.h> // ip4_address_t +#include <vnet/ip/ip6_packet.h> // ip6_address_t + +#else + +#include <netinet/in.h> + +typedef union +{ + u32 as_u32; + struct in_addr as_inaddr; +} ip4_address_t; + +typedef union +{ + u64 as_u64[2]; + u32 as_u32[4]; + u8 as_u8[16]; + struct in6_addr as_in6addr; +} ip6_address_t; + +typedef union +{ + struct + { + u32 pad[3]; + ip4_address_t ip4; + }; + ip6_address_t ip6; +} ip46_address_t; + +#define ip46_address_is_ip4(ip46) (((ip46)->pad[0] | (ip46)->pad[1] | (ip46)->pad[2]) == 0) + +#endif /* ! HICN_VPP_PLUGIN */ + +/** + * @brief Returns the family of an IP address + * @param [in] ip_address - IP address in presentation format + * @return AF_INET or AF_INET6 if successful, -1 otherwise + */ +int get_addr_family (const char *ip_address); + +/* + * Checksum computation + * + * NOTE: VPP provides efficient (incremental) checksum computations + * that we reuse, and provide alternative implementation otherwise. + */ + +#ifndef HICN_VPP_PLUGIN + +typedef u16 ip_csum_t; + +/* + * Checksum update (incremental and non-incremental) + * + * Those functions are already defined in VPP in vnet/ip/ip_packet.h, and we + * borrow this code here. + */ + +static_always_inline u16 +ip_csum_fold (ip_csum_t c) +{ + /* Reduce to 16 bits. */ +#if 0 // uword_bits == 64 + c = (c & (ip_csum_t) 0xffffffff) + (c >> (ip_csum_t) 32); + c = (c & 0xffff) + (c >> 16); +#endif + + c = (c & 0xffff) + (c >> 16); + c = (c & 0xffff) + (c >> 16); + + return c; +} + +static_always_inline ip_csum_t +ip_csum_with_carry (ip_csum_t sum, ip_csum_t x) +{ + ip_csum_t t = sum + x; + return t + (t < x); +} + +/* Update checksum changing field at even byte offset from x -> 0. */ +static_always_inline ip_csum_t +ip_csum_add_even (ip_csum_t c, ip_csum_t x) +{ + ip_csum_t d; + + d = c - x; + + /* Fold in carry from high bit. */ + d -= d > c; + + return d; +} + +/* Update checksum changing field at even byte offset from 0 -> x. */ +static_always_inline ip_csum_t +ip_csum_sub_even (ip_csum_t c, ip_csum_t x) +{ + return ip_csum_with_carry (c, x); +} + +u32 cumulative_hash32 (const void *data, size_t len, u32 lastValue); +u32 hash32 (const void *data, size_t len); +u64 cumulative_hash64 (const void *data, size_t len, u64 lastValue); +u64 hash64 (const void *data, size_t len); +void hicn_packet_dump (uint8_t * buffer, size_t len); + +#endif /* ! HICN_VPP_PLUGIN */ + +/** + * @brief Computes buffer checksum + * @param [in] addr - Pointer to buffer start + * @param [in] size - Size of buffer + * @param [in] init - Checksum initial value + * @return Checksum of specified buffer + */ +always_inline u16 +csum (const void *addr, size_t size, u16 init) +{ + u32 sum = init; + const u16 *bytes = (u16 *) addr; + + while (size > 1) + { + sum += *bytes++; + size -= sizeof (u16); + } + if (size) + { + sum += *(const u8 *) bytes; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + + return (u16) ~ sum; +} + +/* + * Useful aliases + */ + +/* Symmetry with IPPROTO_ICMPV6 */ +#define IPPROTO_ICMPV4 IPPROTO_ICMP + +/* + * Query IP version from packet (either 4 or 6) + * (version is located as same offsets in both protocol headers) + */ +#define HICN_IP_VERSION(packet) ((hicn_header_t *)packet)->v4.ip.version + +#endif /* HICN_COMMON_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/compat.c b/lib/src/compat.c new file mode 100755 index 000000000..7d9eef025 --- /dev/null +++ b/lib/src/compat.c @@ -0,0 +1,1177 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file compat.c + * @brief Implementation of the compatibility layer. + */ + +#include <netinet/in.h> +#include <string.h> // memset +#include <stddef.h> // offsetof + +#include "common.h" +#include "compat.h" +#include "error.h" +#include "header.h" +#include "name.h" +#include "ops.h" + +#define member_size(type, member) sizeof(((type *)0)->member) +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + +#define HICN_NAME_COMPONENT_SIZE 2 + +int +hicn_packet_get_format (const hicn_header_t * h, hicn_format_t * format) +{ + *format = HF_UNSPEC; + + switch (HICN_IP_VERSION (h)) + { + case 4: + switch (h->v4.ip.protocol) + { + case IPPROTO_TCP: + if (h->v4.tcp.flags & AH_FLAG) + *format = HF_INET_TCP_AH; + else + *format = HF_INET_TCP; + break; + case IPPROTO_ICMP: + *format = HF_INET_ICMP; + break; + default: + return HICN_LIB_ERROR_NOT_HICN; + } + break; + case 6: + switch (h->v6.ip.nxt) + { + case IPPROTO_TCP: + if (h->v6.tcp.flags & AH_FLAG) + *format = HF_INET6_TCP_AH; + else + *format = HF_INET6_TCP; + break; + case IPPROTO_ICMPV6: + *format = HF_INET6_ICMP; + break; + default: + return HICN_LIB_ERROR_NOT_HICN; + } + break; + default: + return HICN_LIB_ERROR_NOT_HICN; + } + + return HICN_LIB_ERROR_NONE; +} + +/** + * @brief Convert (former) hICN format into (newer) hICN type + * @param [in] format - hICN format + * @return hICN type, all zero'ed if type is unknown + */ +hicn_type_t +hicn_format_to_type (hicn_format_t format) +{ + switch (format) + { + case HF_INET_TCP: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_TCP,.l1 = + IPPROTO_IP}; + case HF_INET6_TCP: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_TCP,.l1 = + IPPROTO_IPV6}; + case HF_INET_ICMP: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_ICMP,.l1 = + IPPROTO_IP}; + case HF_INET6_ICMP: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_ICMPV6,.l1 = + IPPROTO_IPV6}; + case HF_INET_TCP_AH: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_TCP,.l1 = IPPROTO_IP}; + case HF_INET6_TCP_AH: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_TCP,.l1 = + IPPROTO_IPV6}; + case HF_INET_ICMP_AH: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_ICMP,.l1 = + IPPROTO_IP}; + case HF_INET6_ICMP_AH: + return (hicn_type_t) + { + .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_ICMPV6,.l1 = + IPPROTO_IPV6}; + default: + break; + } + return (hicn_type_t) + { + { + IPPROTO_NONE} + }; +} + +/** + * @brief Parse hICN header and return hICN type + * @param [in] h - hICN header + * @param [out] format - hICN type + * @return hICN error code + * + * This function is used to wrap old API calls to new ones + */ +hicn_type_t +hicn_header_to_type (const hicn_header_t * h) +{ + hicn_format_t format; + hicn_packet_get_format (h, &format); + return hicn_format_to_type (format); +} + +int +hicn_packet_init_header (hicn_format_t format, hicn_header_t * packet) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->init_packet_header (type, &packet->protocol); +} + +int +hicn_packet_compute_checksum (hicn_format_t format, hicn_header_t * h) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->update_checksums (type, &h->protocol, 0, 0); +} + +int +hicn_packet_compute_header_checksum (hicn_format_t format, hicn_header_t * h, + u16 init_sum) +{ + hicn_type_t type = hicn_format_to_type (format); + /* payload_length == ~0: ignore payload */ + return hicn_ops_vft[type.l1]->update_checksums (type, &h->protocol, + init_sum, ~0); +} + +int +hicn_packet_check_integrity (hicn_format_t format, hicn_header_t * h) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->verify_checksums (type, &h->protocol, 0, 0); +} + +int +hicn_packet_get_header_length_from_format (hicn_format_t format, + size_t * header_length) +{ + *header_length = _is_ipv4 (format) * IPV4_HDRLEN; + *header_length += _is_ipv6 (format) * IPV6_HDRLEN; + *header_length += _is_icmp (format) * ICMP_HDRLEN; + *header_length += _is_tcp (format) * TCP_HDRLEN; + *header_length += _is_ah (format) * AH_HDRLEN; + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_get_header_length (hicn_format_t format, const hicn_header_t * h, + size_t * header_length) +{ + hicn_packet_get_header_length_from_format (format, header_length); + int is_ah = _is_ah (format); + int is_ipv4 = _is_ipv4 (format); + int is_ipv6 = _is_ipv6 (format); + // The signature payload is expressed as number of 32 bits words + *header_length += (is_ah * is_ipv4) * (h->v4ah.ah.payloadlen) << 2; + *header_length += (is_ah * is_ipv6) * (h->v6ah.ah.payloadlen) << 2; + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_get_payload_length (hicn_format_t format, const hicn_header_t * h, + size_t * payload_length) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->get_payload_length (type, &h->protocol, + payload_length); +} + +int +hicn_packet_set_payload_length (hicn_format_t format, hicn_header_t * h, + size_t payload_length) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->set_payload_length (type, &h->protocol, + payload_length); +} + +int +hicn_packet_compare (const hicn_header_t * packet1, + const hicn_header_t * packet2) +{ + hicn_type_t type1 = hicn_header_to_type (packet1); + hicn_type_t type2 = hicn_header_to_type (packet2); + + size_t len1, len2; + int rc; + + if (type1.as_u32 != type2.as_u32) + return HICN_LIB_ERROR_UNEXPECTED; + + rc = hicn_ops_vft[type1.l1]->get_length (type1, &packet1->protocol, &len1); + if (PREDICT_FALSE (rc < 0)) + return HICN_LIB_ERROR_UNEXPECTED; + + rc = hicn_ops_vft[type2.l1]->get_length (type2, &packet2->protocol, &len2); + if (PREDICT_FALSE (rc < 0)) + return HICN_LIB_ERROR_UNEXPECTED; + + if (len1 != len2) + return HICN_LIB_ERROR_UNEXPECTED; + + return memcmp ((u8 *) packet1, (u8 *) packet2, len1); + +} + +int +hicn_packet_get_name (hicn_format_t format, const hicn_header_t * h, + hicn_name_t * name, u8 is_interest) +{ + hicn_type_t type = hicn_format_to_type (format); + + if (is_interest) + return hicn_ops_vft[type.l1]->get_interest_name (type, &h->protocol, + name); + else + return hicn_ops_vft[type.l1]->get_data_name (type, &h->protocol, name); +} + +int +hicn_packet_set_name (hicn_format_t format, hicn_header_t * h, + const hicn_name_t * name, u8 is_interest) +{ + hicn_type_t type = hicn_format_to_type (format); + +#ifndef HICN_VPP_PLUGIN + if (name->type & HNT_IOV) + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +#endif /* HICN_VPP_PLUGIN */ + + if (is_interest) + return hicn_ops_vft[type.l1]->set_interest_name (type, &h->protocol, + name); + else + return hicn_ops_vft[type.l1]->set_data_name (type, &h->protocol, name); +} + +int +hicn_packet_set_payload (hicn_format_t format, hicn_header_t * h, + const u8 * payload, u16 payload_length) +{ + hicn_type_t type = hicn_format_to_type (format); + size_t header_length; + int rc; + + rc = + hicn_ops_vft[type.l1]->get_header_length (type, &h->protocol, + &header_length); + if (rc < 0) + return rc; + + memcpy ((u8 *) h + header_length, payload, payload_length); + + return hicn_ops_vft[type.l1]->set_payload_length (type, &h->protocol, + payload_length); +} + +int +hicn_packet_get_payload (hicn_format_t format, const hicn_header_t * h, + u8 ** payload, size_t * payload_size, bool hard_copy) +{ + size_t header_length, payload_length; + int rc; + hicn_type_t type = hicn_format_to_type (format); + + rc = + hicn_ops_vft[type.l1]->get_header_length (type, &h->protocol, + &header_length); + if (rc < 0) + return rc; + + rc = + hicn_ops_vft[type.l1]->get_payload_length (type, &h->protocol, + &payload_length); + if (rc < 0) + return rc; + + if (hard_copy) + { + memcpy (payload, (u8 *) h + header_length, payload_length); + } + else + { + *payload = (u8 *) h + header_length; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_get_locator (hicn_format_t format, const hicn_header_t * h, + ip_address_t * ip_address, bool is_interest) +{ + const void *locator; + int is_ipv4 = (format & HFO_INET); + int is_ipv6 = (format & HFO_INET6) >> 1; + + if (is_ipv4) + { + locator = is_interest ? &h->v4.ip.saddr : &h->v4.ip.daddr; + ip_address->family = AF_INET; + ip_address->prefix_len = IPV4_ADDR_LEN_BITS; + } + else if (is_ipv6) + { + locator = is_interest ? &h->v6.ip.saddr : &h->v6.ip.daddr; + ip_address->family = AF_INET6; + ip_address->prefix_len = IPV6_ADDR_LEN_BITS; + } + else + { + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + memcpy (ip_address->buffer, locator, ip_address_len (ip_address)); + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_locator (hicn_format_t format, hicn_header_t * h, + const ip_address_t * ip_address, bool is_interest) +{ + void *locator; + int is_ipv4 = (format & HFO_INET); + int is_ipv6 = (format & HFO_INET6) >> 1; + + if (is_ipv6) + { + locator = is_interest ? &h->v6.ip.saddr : &h->v6.ip.daddr; + } + else if (is_ipv4) + { + locator = is_interest ? &h->v4.ip.saddr : &h->v4.ip.daddr; + } + else + { + return HICN_LIB_ERROR_INVALID_PARAMETER; + } + + memcpy (locator, ip_address->buffer, ip_address_len (ip_address)); + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_get_signature_size (hicn_format_t format, const hicn_header_t * h, + size_t * bytes) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->get_signature_size (type, &h->protocol, + bytes); +} + +int +hicn_packet_set_signature_size (hicn_format_t format, hicn_header_t * h, + size_t bytes) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->set_signature_size (type, &h->protocol, + bytes); +} + +int +hicn_packet_set_signature_timestamp (hicn_format_t format, hicn_header_t * h, + uint64_t signature_timestamp) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->set_signature_timestamp (type, &h->protocol, + signature_timestamp); +} + +int +hicn_packet_get_signature_timestamp (hicn_format_t format, const hicn_header_t * h, + uint64_t *signature_timestamp) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->get_signature_timestamp (type, &h->protocol, + signature_timestamp); +} + +int +hicn_packet_set_validation_algorithm (hicn_format_t format, hicn_header_t * h, + uint8_t validation_algorithm) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->set_validation_algorithm (type, &h->protocol, + validation_algorithm); +} + +int +hicn_packet_get_validation_algorithm (hicn_format_t format, const hicn_header_t * h, + uint8_t * validation_algorithm) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->get_validation_algorithm (type, &h->protocol, + validation_algorithm); +} + +int +hicn_packet_set_key_id (hicn_format_t format, hicn_header_t * h, + uint8_t *key_id) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->set_key_id (type, &h->protocol, + key_id); +} + +int +hicn_packet_get_key_id (hicn_format_t format, hicn_header_t * h, + uint8_t ** key_id, uint8_t *key_id_length) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->get_key_id (type, &h->protocol, + key_id, key_id_length); +} + +int +hicn_packet_get_hoplimit (const hicn_header_t * h, u8 * hops) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *hops = h->v6.ip.hlim; + break; + case 4: + *hops = h->v4.ip.ttl; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_hoplimit (hicn_header_t * h, u8 hops) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.ip.hlim = hops; + break; + case 4: + h->v4.ip.ttl = hops; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + + +int +hicn_packet_get_lifetime (const hicn_header_t * h, u32 * lifetime) +{ + hicn_type_t type = hicn_header_to_type (h); + return hicn_ops_vft[type.l1]->get_lifetime (type, &h->protocol, + (hicn_lifetime_t *) lifetime); +} + +int +hicn_packet_set_lifetime (hicn_header_t * h, u32 lifetime) +{ + hicn_type_t type = hicn_header_to_type (h); + return hicn_ops_vft[type.l1]->set_lifetime (type, &h->protocol, + (hicn_lifetime_t) lifetime); +} + +int +hicn_packet_get_reserved_bits (const hicn_header_t * h, u8 * reserved_bits) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *reserved_bits = h->v6.tcp.reserved; + break; + case 4: + *reserved_bits = h->v4.tcp.reserved; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_reserved_bits (hicn_header_t * h, u8 reserved_bits) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.reserved = reserved_bits; + break; + case 4: + h->v4.tcp.reserved = reserved_bits; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_get_payload_type (const hicn_header_t * h, + hicn_payload_type_t * payload_type) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *payload_type = ((h->v6.tcp.flags & TCP_FLAG_URG) == TCP_FLAG_URG); + break; + case 4: + *payload_type = ((h->v4.tcp.flags & TCP_FLAG_URG) == TCP_FLAG_URG); + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + if (*payload_type == HPT_UNSPEC) + { + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_payload_type (hicn_header_t * h, + hicn_payload_type_t payload_type) +{ + if (payload_type != HPT_DATA && payload_type != HPT_MANIFEST) + { + return HICN_LIB_ERROR_UNEXPECTED; + } + + switch (HICN_IP_VERSION (h)) + { + case 6: + if (payload_type) + h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_URG; + else + h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_URG; + break; + case 4: + if (payload_type) + h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_URG; + else + h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_URG; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_syn (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_SYN; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_SYN; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_reset_syn (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_SYN; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_SYN; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_test_syn (const hicn_header_t * h, bool * flag) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *flag = h->v6.tcp.flags & TCP_FLAG_SYN; + break; + case 4: + *flag = h->v4.tcp.flags & TCP_FLAG_SYN; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_ack (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_ACK; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_ACK; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_reset_ack (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_ACK; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_ACK; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_test_ack (const hicn_header_t * h, bool * flag) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *flag = h->v6.tcp.flags & TCP_FLAG_ACK; + break; + case 4: + *flag = h->v4.tcp.flags & TCP_FLAG_ACK; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_rst (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_RST; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_RST; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_reset_rst (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_RST; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_RST; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_test_rst (const hicn_header_t * h, bool * flag) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *flag = h->v6.tcp.flags & TCP_FLAG_RST; + break; + case 4: + *flag = h->v4.tcp.flags & TCP_FLAG_RST; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_fin (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_FIN; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_FIN; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_reset_fin (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_FIN; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_FIN; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_test_fin (const hicn_header_t * h, bool * flag) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *flag = h->v6.tcp.flags & TCP_FLAG_FIN; + break; + case 4: + *flag = h->v4.tcp.flags & TCP_FLAG_FIN; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_ece (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_ECE; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_ECE; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_reset_ece (hicn_header_t * h) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_ECE; + break; + case 4: + h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_ECE; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_test_ece (const hicn_header_t * h, bool * flag) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *flag = h->v6.tcp.flags & TCP_FLAG_ECE; + break; + case 4: + *flag = h->v4.tcp.flags & TCP_FLAG_ECE; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_src_port (hicn_header_t * h, u16 src_port) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.sport = htons (src_port); + break; + case 4: + h->v4.tcp.sport = htons (src_port); + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_get_src_port (const hicn_header_t * h, u16 * src_port) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *src_port = ntohs (h->v6.tcp.sport); + break; + case 4: + *src_port = ntohs (h->v4.tcp.sport); + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_set_dst_port (hicn_header_t * h, u16 dst_port) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + h->v6.tcp.dport = htons (dst_port); + break; + case 4: + h->v4.tcp.dport = htons (dst_port); + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_get_dst_port (const hicn_header_t * h, u16 * dst_port) +{ + switch (HICN_IP_VERSION (h)) + { + case 6: + *dst_port = ntohs (h->v6.tcp.dport); + break; + case 4: + *dst_port = ntohs (h->v4.tcp.dport); + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + return HICN_LIB_ERROR_NONE; +} + +int +hicn_packet_copy_header (hicn_format_t format, const hicn_header_t * packet, + hicn_header_t * destination, bool copy_ah) +{ + size_t header_length = _is_ipv4 (format) * IPV4_HDRLEN; + header_length += _is_ipv6 (format) * IPV6_HDRLEN; + header_length += _is_icmp (format) * ICMP_HDRLEN; + header_length += _is_tcp (format) * TCP_HDRLEN; + header_length += _is_ah (format) * copy_ah * AH_HDRLEN; + + memcpy (destination, packet, header_length); + + return HICN_LIB_ERROR_NONE; +} + +#define _INTEREST 1 +#define _DATA 0 + +/* Interest */ + +int +hicn_interest_get_name (hicn_format_t format, const hicn_header_t * interest, + hicn_name_t * name) +{ + return hicn_packet_get_name (format, interest, name, _INTEREST); +} + +int +hicn_interest_set_name (hicn_format_t format, hicn_header_t * interest, + const hicn_name_t * name) +{ + int ret_err = hicn_packet_reset_ece (interest); //interest packet -> ece flag unset + if (ret_err < 0) + return HICN_LIB_ERROR_UNEXPECTED; + return hicn_packet_set_name (format, interest, name, _INTEREST); +} + +int +hicn_interest_get_locator (hicn_format_t format, + const hicn_header_t * interest, + ip_address_t * ip_address) +{ + return hicn_packet_get_locator (format, interest, ip_address, _INTEREST); +} + +int +hicn_interest_set_locator (hicn_format_t format, hicn_header_t * interest, + const ip_address_t * ip_address) +{ + return hicn_packet_set_locator (format, interest, ip_address, _INTEREST); +} + +int +hicn_interest_compare (const hicn_header_t * interest_1, + const hicn_header_t * interest_2) +{ + return hicn_packet_compare (interest_1, interest_2); +} + +int +hicn_interest_get_lifetime (const hicn_header_t * interest, u32 * lifetime) +{ + return hicn_packet_get_lifetime (interest, lifetime); +} + +int +hicn_interest_set_lifetime (hicn_header_t * interest, u32 lifetime) +{ + return hicn_packet_set_lifetime (interest, lifetime); +} + +int +hicn_interest_get_header_length (hicn_format_t format, + const hicn_header_t * interest, + size_t * header_length) +{ + return hicn_packet_get_header_length (format, interest, header_length); +} + +int +hicn_interest_get_payload_length (hicn_format_t format, + const hicn_header_t * interest, + size_t * payload_length) +{ + return hicn_packet_get_payload_length (format, interest, payload_length); +} + +int +hicn_interest_get_payload (hicn_format_t format, + const hicn_header_t * interest, u8 ** payload, + size_t * payload_size, bool hard_copy) +{ + return hicn_packet_get_payload (format, interest, payload, payload_size, + hard_copy); +} + +int +hicn_interest_set_payload (hicn_format_t format, hicn_header_t * interest, + const u8 * payload, size_t payload_length) +{ + return hicn_packet_set_payload (format, interest, payload, payload_length); +} + +int +hicn_interest_reset_for_hash (hicn_format_t format, hicn_header_t * packet) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->reset_interest_for_hash (type, + &packet->protocol); +} + +/* Data */ + +int +hicn_data_get_name (hicn_format_t format, const hicn_header_t * data, + hicn_name_t * name) +{ + return hicn_packet_get_name (format, data, name, _DATA); +} + +int +hicn_data_set_name (hicn_format_t format, hicn_header_t * data, + hicn_name_t * name) +{ + int ret_err = hicn_packet_set_ece (data); //data packet -> ece flag set + if (ret_err < 0) + return HICN_LIB_ERROR_UNEXPECTED; + return hicn_packet_set_name (format, data, name, _DATA); +} + +int +hicn_data_get_locator (hicn_format_t format, const hicn_header_t * data, + ip_address_t * ip_address) +{ + return hicn_packet_get_locator (format, data, ip_address, _DATA); +} + +int +hicn_data_set_locator (hicn_format_t format, hicn_header_t * data, + const ip_address_t * ip_address) +{ + return hicn_packet_set_locator (format, data, ip_address, _DATA); +} + +int +hicn_data_compare (const hicn_header_t * data_1, const hicn_header_t * data_2) +{ + return hicn_packet_compare (data_1, data_2); +} + +int +hicn_data_get_expiry_time (const hicn_header_t * data, u32 * expiry_time) +{ + return hicn_packet_get_lifetime (data, expiry_time); +} + +int +hicn_data_set_expiry_time (hicn_header_t * data, u32 expiry_time) +{ + return hicn_packet_set_lifetime (data, (hicn_lifetime_t) expiry_time); +} + +int +hicn_data_get_header_length (hicn_format_t format, hicn_header_t * data, + size_t * header_length) +{ + return hicn_packet_get_header_length (format, data, header_length); +} + +int +hicn_data_get_payload_length (hicn_format_t format, + const hicn_header_t * data, + size_t * payload_length) +{ + return hicn_packet_get_payload_length (format, data, payload_length); +} + +int +hicn_data_set_payload_type (hicn_header_t * data, + hicn_payload_type_t payload_type) +{ + return hicn_packet_set_payload_type (data, payload_type); +} + +int +hicn_data_get_payload_type (const hicn_header_t * data, + hicn_payload_type_t * payload_type) +{ + return hicn_packet_get_payload_type (data, payload_type); +} + +int +hicn_data_get_path_label (const hicn_header_t * data, u32 * path_label) +{ + hicn_type_t type = hicn_header_to_type (data); + return hicn_ops_vft[type.l1]->get_data_pathlabel (type, &data->protocol, + path_label); +} + +int +hicn_data_set_path_label (hicn_header_t * data, u32 path_label) +{ + hicn_type_t type = hicn_header_to_type (data); + return hicn_ops_vft[type.l1]->set_data_pathlabel (type, &data->protocol, + path_label); +} + +int +hicn_data_set_payload (hicn_format_t format, hicn_header_t * data, + const u8 * payload, size_t payload_length) +{ + return hicn_packet_set_payload (format, data, payload, payload_length); +} + +int +hicn_data_get_payload (hicn_format_t format, const hicn_header_t * data, + u8 ** payload, size_t * payload_size, bool hard_copy) +{ + return hicn_packet_get_payload (format, data, payload, payload_size, + hard_copy); +} + +int +hicn_data_reset_for_hash (hicn_format_t format, hicn_header_t * packet) +{ + hicn_type_t type = hicn_format_to_type (format); + return hicn_ops_vft[type.l1]->reset_interest_for_hash (type, + &packet->protocol); + +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/compat.h b/lib/src/compat.h new file mode 100755 index 000000000..1a1743de2 --- /dev/null +++ b/lib/src/compat.h @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file compat.h + * @brief Implementation of the compatibility layer. + * + * The structure of the core API has evolved to support operations of a variety + * of packet formats in addition to IPv4/TCP and IPv6/TCP, namely with the use + * of ICMP for signalization and AH headers for integrity. The new API format + * has been designed to scale better with the multiplicity of packet formats, + * and provide a unified interface on top. We maintain an interface for the + * former API in this file, which mainly acts as a wrapper on top of new calls. + */ +#ifndef HICN_COMPAT_H +#define HICN_COMPAT_H + +#include "common.h" +#include "header.h" +#include "name.h" + +/* HICN format options */ +#define HFO_INET 1 << 0 +#define HFO_INET6 1 << 1 +#define HFO_TCP 1 << 2 +#define HFO_ICMP 1 << 3 +#define HFO_AH 1 << 4 + +#define _is_ipv4(format) ((format & HFO_INET)) +#define _is_ipv6(format) ((format & HFO_INET6) >> 1) +#define _is_tcp(format) ((format & HFO_TCP) >> 2) +#define _is_icmp(format) ((format & HFO_ICMP) >> 3) +#define _is_ah(format) ((format & HFO_AH) >> 4) + +typedef enum +{ + HF_UNSPEC = 0, + HF_INET_TCP = HFO_INET | HFO_TCP, + HF_INET6_TCP = HFO_INET6 | HFO_TCP, + HF_INET_ICMP = HFO_INET | HFO_ICMP, + HF_INET6_ICMP = HFO_INET6 | HFO_ICMP, + HF_INET_TCP_AH = HFO_INET | HFO_TCP | HFO_AH, + HF_INET6_TCP_AH = HFO_INET6 | HFO_TCP | HFO_AH, + HF_INET_ICMP_AH = HFO_INET | HFO_ICMP | HFO_AH, + HF_INET6_ICMP_AH = HFO_INET6 | HFO_ICMP | HFO_AH +} hicn_format_t; + +/** + * Maximum Size of the hICN header (the effective size will depend on the + * underlying IP version) + */ +#define HICN_HDR_LEN sizeof(hicn_header_t) + +/** + * Minimum required header length to determine the type and length of a supposed + * hICN packet. + * This should be equal to the maximum value over all possible hICN packet + * formats, and less than the minimum possible IP packet size. + */ +#define HICN_V6_MIN_HDR_LEN 6 /* bytes */ +#define HICN_V4_MIN_HDR_LEN 4 /* bytes */ + +// #define HICN_MIN_HDR_LEN ((HICN_V6_MIN_HDR_LEN > HICN_V4_MIN_HDR_LEN) ? HICN_V6_MIN_HDR_LEN : HICN_V4_MIN_HDR_LEN) +#define HICN_MIN_HDR_LEN HICN_V6_MIN_HDR_LEN + +/** + * @brief Parse packet headers and return hICN format + * @param [in] format - hICN Format + * @param [in, out] packet - Buffer containing the hICN header to be initialized + * @return hICN error code + */ +int hicn_packet_init_header (hicn_format_t format, hicn_header_t * packet); + +/** + * @brief Parse packet headers and return hICN format + * @param [in] h - hICN header + * @param [out] format - hICN format + * @return hICN error code + */ +int hicn_packet_get_format (const hicn_header_t * packet, + hicn_format_t * format); + +/** + * @brief Update checksums in packet headers + * @param [in] format - hICN format + * @param [in,out] packet - packet header + * @return hICN error code + */ +int hicn_packet_compute_checksum (hicn_format_t format, + hicn_header_t * packet); + +/** + * @brief compute the checksum of the packet header, adding init_sum to the final value + * @param [in] format - hICN format + * @param [in,out] packet - packet header + * @param [in] init_sum - value to add to the final checksum + * @return hICN error code + */ +int hicn_packet_compute_header_checksum (hicn_format_t format, + hicn_header_t * packet, + u16 init_sum); + +/** + * @brief Verify checksums in packet headers + * @param [in] format - hICN format + * @param [in,out] packet - packet header + * @return hICN error code + */ +int hicn_packet_check_integrity (hicn_format_t format, + hicn_header_t * packet); + +// this is not accounted here +/** + * @brief Return total length of hicn headers (but signature payload) + * @param [in] format - hICN format + * @param [out] header_length - Total length of headers + * @return hICN error code + */ +int hicn_packet_get_header_length_from_format (hicn_format_t format, + size_t * header_length); + +/** + * @brief Return total length of hicn headers (before payload) + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] header_length - Total length of headers + * @return hICN error code + */ +int hicn_packet_get_header_length (hicn_format_t format, + const hicn_header_t * packet, + size_t * header_length); + +/** + * @brief Return payload length + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] payload_length - payload length + * @return hICN error code + */ +int hicn_packet_get_payload_length (hicn_format_t format, + const hicn_header_t * packet, + size_t * payload_length); + +/** + * @brief Sets payload length + * @param [in] format - hICN format + * @param [in,out] packet - packet header + * @param [in] payload_length - payload length + * @return hICN error code + */ +int hicn_packet_set_payload_length (hicn_format_t format, + hicn_header_t * packet, + const size_t payload_length); + +/** + * @brief Compare two hICN packets + * @param [in] packet_1 - First packet + * @param [in] packet_2 - Second packet + * @return 0 if both packets are considered equal, any other value otherwise. + */ +int hicn_packet_compare (const hicn_header_t * packet1, + const hicn_header_t * packet2); + +/** + * @brief Retrieve the name of an interest/data packet + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] name - name holding the result + * @param [in] is_interest - Flag to determine whether it is an interest (1) or + * data packet (0) + * @return hICN error code + */ +int hicn_packet_get_name (hicn_format_t format, const hicn_header_t * packet, + hicn_name_t * name, u8 is_interest); + +/** + * @brief Sets the name of an interest/data packet + * @param [in] format - hICN format + * @param [in,out] packet - packet header + * @param [in] name - name to set into packet + * @param [in] is_interest - Flag to determine whether it is an interest (1) or + * data packet (0) + * @return hICN error code + */ +int hicn_packet_set_name (hicn_format_t format, hicn_header_t * packet, + const hicn_name_t * name, u8 is_interest); + +/** + * @brief Sets the payload of a packet + * @param [in] format - hICN format + * @param [in,out] packet - packet header + * @param [in] payload - payload to set + * @param [in] payload_length - size of the payload to set + * @return hICN error code + * + * NOTE: + * - The buffer holding payload is assumed sufficiently large + * - This function updates header fields with the new length, but no checksum. + */ +int hicn_packet_set_payload (hicn_format_t format, hicn_header_t * packet, + const u8 * payload, u16 payload_length); + +/** + * @brief Retrieves the payload of a packet + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] payload - pointer to buffer for storing the result + * @param [out] payload_length - size of the retreived payload + * @param [in] hard_copy - Flag : if true (eg. 1), a copy of the payload is made + * into the payload buffer, otherwise (0) the pointer is changed to point to the payload offset in the packet. + * @return hICN error code + * + * NOTE: + * - The buffer holding payload is assumed sufficiently large + */ +int hicn_packet_get_payload (hicn_format_t format, + const hicn_header_t * packet, u8 ** payload, + size_t * payload_size, bool hard_copy); + +/** + * @brief Retrieve the locator of an interest / data packet + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] ip_address - retrieved locator + * @param [in] is_interest - Flag to determine whether it is an interest (1) or + * data packet (0) + * @return hICN error code + */ +int hicn_packet_get_locator (hicn_format_t format, + const hicn_header_t * packet, + ip_address_t * ip_address, bool is_interest); + +/** + * @brief Sets the locator of an interest / data packet + * @param [in] format - hICN format + * @param [in,out] packet - packet header + * @param [out] ip_address - retrieved locator + * @param [in] is_interest - Flag to determine whether it is an interest (1) or + * data packet (0) + * @return hICN error code + */ +int hicn_packet_set_locator (hicn_format_t format, hicn_header_t * packet, + const ip_address_t * ip_address, + bool is_interest); + +/** + * @brief Retrieves the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] bytes - Retrieved signature size + * @return hICN error code + */ +int hicn_packet_get_signature_size (hicn_format_t format, + const hicn_header_t * packet, + size_t * bytes); + +/** + * @brief Sets the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [in] bytes - Retrieved signature size + * @return hICN error code + */ +int hicn_packet_set_signature_size (hicn_format_t format, + hicn_header_t * packet, size_t bytes); + +/** + * @brief Sets the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [in] signature_timestamp - Signature timestamp to set + * @return hICN error code + */ +int hicn_packet_set_signature_timestamp (hicn_format_t format, hicn_header_t * h, + uint64_t signature_timestamp); + +/** + * @brief Sets the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] signature_timestamp - Retrieved signature timestamp + * @return hICN error code + */ +int hicn_packet_get_signature_timestamp (hicn_format_t format, const hicn_header_t * h, + uint64_t *signature_timestamp); + +/** + * @brief Sets the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [in] validation_algorithm - Validation algorithm to set + * @return hICN error code + */ +int hicn_packet_set_validation_algorithm (hicn_format_t format, hicn_header_t * h, + uint8_t validation_algorithm); + +/** + * @brief Sets the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] validation_algorithm - Retrieved validation algorithm + * @return hICN error code + */ +int hicn_packet_get_validation_algorithm (hicn_format_t format, const hicn_header_t * h, + uint8_t * validation_algorithm); + +/** + * @brief Sets the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [in] key_id - Key id to set + * @return hICN error code + */ +int hicn_packet_set_key_id (hicn_format_t format, hicn_header_t * h, + uint8_t *key_id); + +/** + * @brief Sets the signature size + * @param [in] format - hICN format + * @param [in] packet - packet header + * @param [out] key_id - Retrieved key id + * @return hICN error code + */ +int hicn_packet_get_key_id (hicn_format_t format, hicn_header_t * h, + uint8_t ** key_id, uint8_t *key_id_length); + +/** + * @brief Retrieves the packet hop limit + * @param [in] packet - packet header + * @param [out] hops - Retrieved hop limit + * @return hICN error code + */ +int hicn_packet_get_hoplimit (const hicn_header_t * packet, u8 * hops); + +/** + * @brief Sets the packet hop limit + * @param [in] packet - packet header + * @param [in] hops - Hop limit to set + * @return hICN error code + */ +int hicn_packet_set_hoplimit (hicn_header_t * packet, u8 hops); + +int hicn_packet_copy_header (hicn_format_t format, + const hicn_header_t * packet, + hicn_header_t * destination, bool copy_ah); + +int hicn_packet_get_lifetime (const hicn_header_t * packet, u32 * lifetime); +int hicn_packet_set_lifetime (hicn_header_t * packet, u32 lifetime); +int hicn_packet_get_reserved_bits (const hicn_header_t * packet, + u8 * reserved_bits); +int hicn_packet_set_reserved_bits (hicn_header_t * packet, + const u8 reserved_bits); +int hicn_packet_get_payload_type (const hicn_header_t * packet, + hicn_payload_type_t * payload_type); +int hicn_packet_set_payload_type (hicn_header_t * packet, + const hicn_payload_type_t payload_type); + +int hicn_packet_set_syn (hicn_header_t * packet); +int hicn_packet_reset_syn (hicn_header_t * packet); +int hicn_packet_test_syn (const hicn_header_t * packet, bool * flag); +int hicn_packet_set_ack (hicn_header_t * packet); +int hicn_packet_reset_ack (hicn_header_t * packet); +int hicn_packet_test_ack (const hicn_header_t * packet, bool * flag); +int hicn_packet_set_rst (hicn_header_t * packet); +int hicn_packet_reset_rst (hicn_header_t * packet); +int hicn_packet_test_rst (const hicn_header_t * packet, bool * flag); +int hicn_packet_set_fin (hicn_header_t * packet); +int hicn_packet_reset_fin (hicn_header_t * packet); +int hicn_packet_test_fin (const hicn_header_t * packet, bool * flag); +int hicn_packet_set_ece (hicn_header_t * packet); +int hicn_packet_reset_ece (hicn_header_t * packet); +int hicn_packet_test_ece (const hicn_header_t * packet, bool * flag); + +int hicn_packet_set_src_port (hicn_header_t * packet, u16 src_port); +int hicn_packet_get_src_port (const hicn_header_t * packet, u16 * src_port); +int hicn_packet_set_dst_port (hicn_header_t * packet, u16 dst_port); +int hicn_packet_get_dst_port (const hicn_header_t * packet, u16 * dst_port); + +/* Interest */ + +int hicn_interest_get_name (hicn_format_t format, + const hicn_header_t * interest, + hicn_name_t * name); +int hicn_interest_set_name (hicn_format_t format, hicn_header_t * interest, + const hicn_name_t * name); +int hicn_interest_get_locator (hicn_format_t format, + const hicn_header_t * interest, + ip_address_t * ip_address); +int hicn_interest_set_locator (hicn_format_t format, hicn_header_t * interest, + const ip_address_t * ip_address); +int hicn_interest_compare (const hicn_header_t * interest_1, + const hicn_header_t * interest_2); +int hicn_interest_set_lifetime (hicn_header_t * interest, u32 lifetime); +int hicn_interest_get_lifetime (const hicn_header_t * interest, + u32 * lifetime); +int hicn_interest_get_header_length (hicn_format_t format, + const hicn_header_t * interest, + size_t * header_length); +int hicn_interest_get_payload_length (hicn_format_t format, + const hicn_header_t * interest, + size_t * payload_length); +int hicn_interest_set_payload (hicn_format_t format, hicn_header_t * interest, + const u8 * payload, size_t payload_length); +int hicn_interest_get_payload (hicn_format_t format, + const hicn_header_t * interest, u8 ** payload, + size_t * payload_size, bool hard_copy); +int hicn_interest_reset_for_hash (hicn_format_t format, + hicn_header_t * packet); + +/* Data */ + +int hicn_data_get_name (hicn_format_t format, const hicn_header_t * data, + hicn_name_t * name); +int hicn_data_set_name (hicn_format_t format, hicn_header_t * data, + hicn_name_t * name); +int hicn_data_get_locator (hicn_format_t format, const hicn_header_t * data, + ip_address_t * ip_address); +int hicn_data_set_locator (hicn_format_t format, hicn_header_t * data, + const ip_address_t * ip_address); +int hicn_data_compare (const hicn_header_t * data_1, + const hicn_header_t * data_2); +int hicn_data_get_expiry_time (const hicn_header_t * data, u32 * expiry_time); +int hicn_data_set_expiry_time (hicn_header_t * data, u32 expiry_time); +int hicn_data_get_header_length (hicn_format_t format, hicn_header_t * data, + size_t * header_length); +int hicn_data_get_payload_length (hicn_format_t format, + const hicn_header_t * data, + size_t * payload_length); +int hicn_data_get_path_label (const hicn_header_t * data, u32 * path_label); +int hicn_data_set_path_label (hicn_header_t * data, u32 path_label); +int hicn_data_get_payload (hicn_format_t format, const hicn_header_t * data, + u8 ** payload, size_t * payload_size, + bool hard_copy); +int hicn_data_set_payload (hicn_format_t format, hicn_header_t * data, + const u8 * payload, size_t payload_length); +int hicn_data_get_payload_type (const hicn_header_t * data, + hicn_payload_type_t * payload_type); +int hicn_data_set_payload_type (hicn_header_t * data, + hicn_payload_type_t payload_type); +int hicn_data_reset_for_hash (hicn_format_t format, hicn_header_t * packet); + +#endif /* HICN_COMPAT_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/error.c b/lib/src/error.c new file mode 100755 index 000000000..865e2b47d --- /dev/null +++ b/lib/src/error.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file error.c + * @brief Implementation of error management functions. + */ + +#include "error.h" + +const char *HICN_LIB_ERROR_STRING[] = { +#define _(a,b,c) [b] = c, + foreach_libhicn_error +#undef _ +}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/error.h b/lib/src/error.h new file mode 100755 index 000000000..3e027c4e5 --- /dev/null +++ b/lib/src/error.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file error.h + * @brief Error management functions. + */ +#ifndef HICN_ERROR_H +#define HICN_ERROR_H + +/****************************************************************************** + * Error definitions + ******************************************************************************/ + +#define foreach_libhicn_error \ +_(NONE, 0, "OK") \ +_(UNSPECIFIED, 128, "Unspecified Error") \ +_(NOT_IMPLEMENTED, 180, "Function not yet implemented") \ +_(NOT_HICN, 202, "Non hICN packet") \ +_(UNKNOWN_ADDRESS, 210, "Unknown address") \ +_(INVALID_PARAMETER, 220, "Invalid parameter") \ +_(INVALID_IP_ADDRESS, 221, "Invalid IP address") \ +_(CORRUPTED_PACKET, 222, "Corrupted packet ") \ +_(UNEXPECTED, 298, "Unexpected error") + +typedef enum +{ +#define _(a,b,c) HICN_LIB_ERROR_##a = (-b), + foreach_libhicn_error +#undef _ + HICN_LIB_N_ERROR, +} hicn_lib_error_t; + +extern const char *HICN_LIB_ERROR_STRING[]; + +#define hicn_strerror(errno) (char *)(HICN_LIB_ERROR_STRING[-errno]) + +#endif /* HICN_ERROR_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/header.h b/lib/src/header.h new file mode 100755 index 000000000..3864064f2 --- /dev/null +++ b/lib/src/header.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file header.h + * @brief hICN header data structures. + * details. + */ +#ifndef HICN_HEADER_H +#define HICN_HEADER_H + +#include "common.h" +#include "protocol.h" + + +typedef struct +{ + _ipv6_header_t ip; + union + { + _tcp_header_t tcp; + _icmp_header_t icmp; + _icmp_wldr_header_t wldr; + }; +} hicn_v6_hdr_t; + +typedef struct +{ + _ipv6_header_t ip; + union + { + struct + { + _tcp_header_t tcp; + _ah_header_t ah; + }; + struct + { + _icmp_header_t icmp; + _ah_header_t icmp_ah; + }; + }; +} hicn_v6ah_hdr_t; + +typedef struct +{ + _ipv4_header_t ip; + union + { + _tcp_header_t tcp; + _icmp_header_t icmp; + _icmp_wldr_header_t wldr; + }; +} hicn_v4_hdr_t; + +typedef struct +{ + _ipv4_header_t ip; + union + { + struct + { + _tcp_header_t tcp; + _ah_header_t ah; + }; + struct + { + _icmp_header_t icmp; + _ah_header_t icmp_ah; + }; + }; +} hicn_v4ah_hdr_t; + +typedef union +{ + /* To deprecate as redundant with hicn_type_t */ + hicn_v6_hdr_t v6; + hicn_v6ah_hdr_t v6ah; + hicn_v4_hdr_t v4; + hicn_v4ah_hdr_t v4ah; + + hicn_protocol_t protocol; +} hicn_header_t; + +#endif /* HICN_HEADER_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/hicn.h b/lib/src/hicn.h new file mode 100755 index 000000000..749fd4247 --- /dev/null +++ b/lib/src/hicn.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file hicn.h + * @brief hICN master include file. + * + * Reference: https://tools.ietf.org/html/draft-muscariello-intarea-hicn + * + * This file is the entry point for projects to libhicn, which provides a + * reference implementation for hICN specifications [1], including: + * - naming + * - packet headers + * - protocol mappings (IPv4, IPv6, TCP, ICMP, AH) + * - protocol independent packet operations + * - helpers for additional features such as Wireless Loss Detection and + * Recovery (WLDR) [2], Anchorless Mobility Management (hICN-AMM) [3], + * including MAP-Me producer mobility mechanisms [4]. + * + * [1] Hybrid Information-Centric Networking + * L. Muscariello, G. Carofiglio, J. Augé, M. Papalini + * IETF draft (intarea) @ https://tools.ietf.org/html/draft-muscariello-intarea-hicn + * + * [2] Leveraging ICN in-network control for loss detection and recovery in wireless mobile networks + * G. Carofiglio, L. Muscariello, M. Papalini, N. Rozhnova, X. Zeng + * In proc. ICN'2016, Kyoto, JP + * + * [3] Anchorless mobility through hICN + * J. Augé, G. Carofiglio, L. Muscariello, M. Papalini + * IETF draft (DMM) @ https://tools.ietf.org/html/draft-auge-dmm-hicn-mobility + * + * + * [4] MAP-Me : Managing Anchorless Mobility in Content Centric Networking + * J. Augé, G. Carofiglio, L. Muscariello, M. Papalini + * IRTF draft (ICNRG) @ https://tools.ietf.org/html/draft-irtf-icnrg-mapme + */ + +#ifndef HICN__H +#define HICN__H + +#ifdef HICN_VPP_PLUGIN + +#include <hicn/header.h> +#include <hicn/name.h> +#include <hicn/ops.h> +#include <hicn/mapme.h> + +#else + +#include <hicn/error.h> +#include <hicn/header.h> +#include <hicn/name.h> +#include <hicn/ops.h> +#include <hicn/mapme.h> +#include <hicn/compat.h> + +#endif + +#endif /* HICN__H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/mapme.c b/lib/src/mapme.c new file mode 100755 index 000000000..e4c5ee1f2 --- /dev/null +++ b/lib/src/mapme.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file mapme.c + * @brief Implementation of MAP-Me anchorless producer mobility management. + */ + +#include "mapme.h" +#include "common.h" +#include "error.h" + +#include "protocol/ipv4.h" +#include "protocol/ipv6.h" + +size_t +hicn_mapme_v4_create_packet (u8 * buf, const hicn_prefix_t * prefix, + const mapme_params_t * params) +{ + hicn_mapme_v4_header_t *mh = (hicn_mapme_v4_header_t *) buf; + /* *INDENT-OFF* */ + *mh = (hicn_mapme_v4_header_t) { + .ip = { + .version_ihl = (IPV4_DEFAULT_VERSION << 4) | (0x0f & IPV4_DEFAULT_IHL), + .tos = IPV4_DEFAULT_TOS, + .len = HICN_MAPME_V4_HDRLEN, + .id = htons(IPV4_DEFAULT_ID), + .frag_off = htons(IPV4_DEFAULT_FRAG_OFF), + .ttl = HICN_MAPME_TTL, + .protocol = IPPROTO_ICMP, + .csum = 0, + .saddr.as_u32 = 0, + .daddr = prefix->name.ip4, + }, + .icmp = { + .type = ((params->type == UPDATE) || (params->type == NOTIFICATION)) + ? HICN_MAPME_ICMP_TYPE_IPV4 + : HICN_MAPME_ICMP_TYPE_ACK_IPV4, + .code = HICN_MAPME_ICMP_CODE, + .csum = 0, + }, + .icmp_rd = { + .ip = prefix->name.ip4, + }, + .seq = htonl(params->seq), + .len = prefix->len, + }; + /* *INDENT-ON* */ + + return HICN_MAPME_V4_HDRLEN; +} + +size_t +hicn_mapme_v6_create_packet (u8 * buf, const hicn_prefix_t * prefix, + const mapme_params_t * params) +{ + hicn_mapme_v6_header_t *mh = (hicn_mapme_v6_header_t *) buf; + /* *INDENT-OFF* */ + *mh = (hicn_mapme_v6_header_t) { + .ip = { + .saddr = {{0}}, + .daddr = prefix->name.ip6, + .version_class_flow = htonl( + (IPV6_DEFAULT_VERSION << 28) | + (IPV6_DEFAULT_TRAFFIC_CLASS << 20) | + (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)), + .len = htons(HICN_MAPME_V6_HDRLEN - IPV6_HDRLEN), + .nxt = IPPROTO_ICMPV6, + .hlim = HICN_MAPME_TTL, + }, + .icmp = { + .type = ((params->type == UPDATE) || (params->type == NOTIFICATION)) + ? HICN_MAPME_ICMP_TYPE_IPV6 + : HICN_MAPME_ICMP_TYPE_ACK_IPV6, + .code = HICN_MAPME_ICMP_CODE, + .csum = 0, + }, + .icmp_rd = { + .res = 0, + .tgt = prefix->name.ip6, + .dst = prefix->name.ip6, + }, + .seq = htonl(params->seq), + .len = prefix->len, + }; + /* *INDENT-ON* */ + return HICN_MAPME_V6_HDRLEN; +} + +size_t +hicn_mapme_create_packet (u8 * buf, const hicn_prefix_t * prefix, + const mapme_params_t * params) +{ + /* We currently ignore subsequent protocol definitions */ + if (PREDICT_TRUE (params->protocol == IPPROTO_IPV6)) + return hicn_mapme_v6_create_packet (buf, prefix, params); + else + return hicn_mapme_v4_create_packet (buf, prefix, params); +} + +size_t +hicn_mapme_v4_create_ack (u8 * buf, const mapme_params_t * params) +{ + ip4_address_t tmp; // tmp storage for swapping IP addresses for ACK + + hicn_mapme_v4_header_t *mh = (hicn_mapme_v4_header_t *) buf; + tmp = mh->ip.daddr; + mh->ip.daddr = mh->ip.saddr; + mh->ip.saddr = tmp; + mh->ip.ttl = HICN_MAPME_TTL; + mh->icmp.type = (params->type == UPDATE) ? UPDATE_ACK : NOTIFICATION_ACK; + mh->icmp.csum = 0; + + return HICN_MAPME_V4_HDRLEN; +} + +size_t +hicn_mapme_v6_create_ack (u8 * buf, const mapme_params_t * params) +{ + ip6_address_t tmp; // tmp storage for swapping IP addresses for ACK + + hicn_mapme_v6_header_t *mh = (hicn_mapme_v6_header_t *) buf; + tmp = mh->ip.daddr; + mh->ip.daddr = mh->ip.saddr; + mh->ip.saddr = tmp; + mh->ip.hlim = HICN_MAPME_TTL; + mh->icmp.type = (params->type == UPDATE) ? UPDATE_ACK : NOTIFICATION_ACK; + mh->icmp.csum = 0; + + return HICN_MAPME_V6_HDRLEN; +} + +size_t +hicn_mapme_create_ack (u8 * buf, const mapme_params_t * params) +{ + /* We currently ignore subsequent protocol definitions */ + if (PREDICT_TRUE (params->protocol == IPPROTO_IPV6)) + return hicn_mapme_v6_create_ack (buf, params); + else + return hicn_mapme_v4_create_ack (buf, params); +} + +int +hicn_mapme_v4_parse_packet (const u8 * packet, hicn_prefix_t * prefix, + mapme_params_t * params) +{ + hicn_mapme_v4_header_t *mh = (hicn_mapme_v4_header_t *) packet; + + /* *INDENT-OFF* */ + *prefix = (hicn_prefix_t) { + .name = { + .ip4 = HICN_MAPME_TYPE_IS_IU (mh->icmp.type) ? mh->ip.daddr : mh->ip.saddr, + }, + .len = mh->len, + }; + + *params = (mapme_params_t) { + .protocol = IPPROTO_IP, + .type = (mh->icmp.type == HICN_MAPME_ICMP_TYPE_IPV4) ? UPDATE : UPDATE_ACK, + .seq = ntohl (mh->seq), + }; + /* *INDENT-ON* */ + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_mapme_v6_parse_packet (const u8 * packet, hicn_prefix_t * prefix, + mapme_params_t * params) +{ + hicn_mapme_v6_header_t *mh = (hicn_mapme_v6_header_t *) packet; + + /* *INDENT-OFF* */ + *prefix = (hicn_prefix_t) { + .name = { + .ip6 = HICN_MAPME_TYPE_IS_IU (mh->icmp.type) ? mh->ip.daddr : mh->ip.saddr, + }, + .len = mh->len, + }; + + *params = (mapme_params_t) { + .protocol = IPPROTO_IPV6, + .type = (mh->icmp.type == HICN_MAPME_ICMP_TYPE_IPV6) ? UPDATE : UPDATE_ACK, + .seq = ntohl (mh->seq), + }; + /* *INDENT-ON* */ + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_mapme_parse_packet (const u8 * packet, hicn_prefix_t * prefix, + mapme_params_t * params) +{ + switch (HICN_IP_VERSION (packet)) + { + case 4: + return hicn_mapme_v4_parse_packet (packet, prefix, params); + case 6: + return hicn_mapme_v6_parse_packet (packet, prefix, params); + default: + return HICN_LIB_ERROR_UNEXPECTED; + } +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/mapme.h b/lib/src/mapme.h new file mode 100755 index 000000000..460c15282 --- /dev/null +++ b/lib/src/mapme.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file mapme.h + * @brief MAP-Me anchorless producer mobility management. + */ +#ifndef HICN_MAPME_H +#define HICN_MAPME_H + +#include <stdint.h> // u32 +#include <stdbool.h> + +#include "common.h" +#include "protocol.h" +#include "ops.h" + +/** + * @brief MAP-Me configuration options + */ +typedef struct +{ + /** MAP-Me enabled flag (default: false) */ + bool enabled; + /** timescale (T_U parameter) in ms (default: 0 for no notifications) */ + u32 timescale; + /** retransmission timer in ms (default: 50) */ + u32 retx; + /** + * Discovery enabled flag (default: true, should be true if mandatory is + * notifications are enabled) + */ + bool discovery; +} hicn_mapme_conf_t; + +/** @brief Default MAP-Me configuration */ +static const hicn_mapme_conf_t hicn_mapme_conf = { + .enabled = false, + .timescale = 0, + .retx = 50, + .discovery = true, +}; + +/** @brief MAP-Me update sequence number */ +typedef u32 seq_t; + +/** @brief MAP-Me packet types */ +typedef enum +{ + UNKNOWN, + UPDATE, + UPDATE_ACK, + NOTIFICATION, + NOTIFICATION_ACK, +} hicn_mapme_type_t; + +/** @brief MAP-Me parameters (excluding those contained in * hicn_prefix_t) */ +typedef struct +{ + int protocol; + hicn_mapme_type_t type; + seq_t seq; +} mapme_params_t; + + +/* MAP-Me API */ +size_t hicn_mapme_create_packet (u8 * buf, const hicn_prefix_t * prefix, + const mapme_params_t * params); +size_t hicn_mapme_create_ack (u8 * buf, const mapme_params_t * params); +int hicn_mapme_parse_packet (const u8 * packet, hicn_prefix_t * prefix, + mapme_params_t * params); + +/* Implementation & parsing : ICMP Redirect */ + +#define HEADER_TYPE_MAPME4 (hicn_type_t) {0, IPPROTO_ICMPRD, IPPROTO_ICMP, IPPROTO_IP} +#define HEADER_TYPE_MAPME6 (hicn_type_t) {0, IPPROTO_ICMPRD, IPPROTO_ICMP, IPPROTO_IPV6} + +#define HICN_MAPME_ACK_FLAG (0x20 | 0x60) + +#define HICN_MAPME_ICMP_TYPE_IPV4 5 +#define HICN_MAPME_ICMP_TYPE_IPV6 137 +#define HICN_MAPME_ICMP_TYPE_ACK_IPV4 (HICN_MAPME_ICMP_TYPE_IPV4 | HICN_MAPME_ACK_FLAG) +#define HICN_MAPME_ICMP_TYPE_ACK_IPV6 (HICN_MAPME_ICMP_TYPE_IPV6 | HICN_MAPME_ACK_FLAG) +#define HICN_MAPME_ICMP_CODE 0 /* Redirect Datagrams for the Network (or subnet) */ + +#define HICN_MAPME_TYPE_IS_IU(type) ((type == HICN_MAPME_ICMP_TYPE_IPV4) || (type == HICN_MAPME_ICMP_TYPE_IPV6)) +#define HICN_MAPME_TYPE_IS_IU_ACK(type) ((type == HICN_MAPME_ICMP_TYPE_ACK_IPV4) || (type == HICN_MAPME_ICMP_TYPE_ACK_IPV6)) + +#define HICN_MAPME_IS_IU(type, code) (HICN_MAPME_TYPE_IS_IU(type) && (code == HICN_MAPME_ICMP_CODE)) +#define HICN_MAPME_IS_ACK(type, code) (HICN_MAPME_TYPE_IS_IU_ACK(type) && (code == HICN_MAPME_ICMP_CODE)) + +#define HICN_IS_MAPME(type, code) (HICN_MAPME_IS_IU(type, code) || HICN_MAPME_IS_ACK(type, code)) + +/* Fast check for ACK flag */ +#define HICN_MAPME_IS_ACK_FAST(icmp_type) (icmp_type & HICN_MAPME_ACK_FLAG) + +/* Default TTL */ +#define HICN_MAPME_TTL 255 // typical for redirect (ref?) + +/** @brief MAP-Me packet header for IPv4 */ +typedef struct __attribute__ ((packed)) +{ + _ipv4_header_t ip; + _icmp_header_t icmp; + _icmprd4_header_t icmp_rd; + seq_t seq; + u8 len; + u8 _pad[3]; +} hicn_mapme_v4_header_t; + +/** @brief MAP-Me packet header for IPv6 */ +typedef struct __attribute__ ((packed)) +{ + _ipv6_header_t ip; + _icmp_header_t icmp; + _icmprd_header_t icmp_rd; + seq_t seq; + u8 len; + u8 _pad[3]; +} hicn_mapme_v6_header_t; + +/** @brief MAP-Me packet header (IP version agnostic) */ +typedef union +{ + hicn_mapme_v4_header_t v4; + hicn_mapme_v6_header_t v6; +} hicn_mapme_header_t; + +#define HICN_MAPME_V4_HDRLEN sizeof(hicn_mapme_v4_header_t) +#define HICN_MAPME_V6_HDRLEN sizeof(hicn_mapme_v6_header_t) + +#endif /* HICN_MAPME_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/name.c b/lib/src/name.c new file mode 100755 index 000000000..6e5711252 --- /dev/null +++ b/lib/src/name.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file name.c + * @brief Implementation of hICN name helpers. + */ + +#include <arpa/inet.h> // inet_ptin +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> // strtoul +#include <string.h> // memcpy + +#include "common.h" +#include "error.h" +#include "name.h" + +#define DUMMY_PORT ntohs(1234) + +#if ! HICN_VPP_PLUGIN +int +hicn_name_create (const char *ip_address, u32 id, hicn_name_t * name) +{ + int af, rc; + + af = get_addr_family (ip_address); + + switch (af) + { + case AF_INET: + if (name->type == HNT_UNSPEC) + { + name->type = HNT_CONTIGUOUS_V4; + } + name->len = IPV4_ADDR_LEN; + break; + case AF_INET6: + if (name->type == HNT_UNSPEC) + { + name->type = HNT_CONTIGUOUS_V6; + } + name->len = IPV6_ADDR_LEN; + break; + default: + return HICN_LIB_ERROR_INVALID_IP_ADDRESS; + } + + if ((name->type != HNT_CONTIGUOUS_V4) && (name->type != HNT_CONTIGUOUS_V6)) + { + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + rc = inet_pton (af, ip_address, name->buffer); + if (rc <= 0) + { + return HICN_LIB_ERROR_UNKNOWN_ADDRESS; + } + *(u32 *) (name->buffer + name->len) = id; + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_create_from_ip_address (const ip_address_t * ip_address, u32 id, + hicn_name_t * name) +{ + switch (ip_address->family) + { + case AF_INET: + if (name->type == HNT_UNSPEC) + { + name->type = HNT_CONTIGUOUS_V4; + } + break; + case AF_INET6: + if (name->type == HNT_UNSPEC) + { + name->type = HNT_CONTIGUOUS_V6; + } + break; + default: + return HICN_LIB_ERROR_INVALID_IP_ADDRESS; + } + + name->len = ip_address->prefix_len; + if ((name->type != HNT_CONTIGUOUS_V4) && (name->type != HNT_CONTIGUOUS_V6)) + { + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + memcpy (name->buffer, ip_address->buffer, ip_address_len (ip_address)); + *(u32 *) (name->buffer + name->len) = id; + + return HICN_LIB_ERROR_NONE; +} + +u8 +hicn_name_get_length (const hicn_name_t * name) +{ + return name->len; +} + +int +hicn_name_compare (const hicn_name_t * name_1, const hicn_name_t * name_2, + bool consider_segment) +{ + hicn_name_t *name1 = (hicn_name_t *) name_1; + hicn_name_t *name2 = (hicn_name_t *) name_2; + + if ((name1->type == HNT_CONTIGUOUS_V4 && name2->type == HNT_CONTIGUOUS_V6) + || (name1->type == HNT_CONTIGUOUS_V6 + && name2->type == HNT_CONTIGUOUS_V4)) + { + return -1; + } + + if ((name1->type == HNT_IOV_V4 && name2->type == HNT_IOV_V6) || + (name1->type == HNT_IOV_V6 && name2->type == HNT_IOV_V4)) + { + return -1; + } + + if ((name1->type == HNT_IOV_V4 && name2->type == HNT_CONTIGUOUS_V6) || + (name1->type == HNT_IOV_V6 && name2->type == HNT_CONTIGUOUS_V4)) + { + return -1; + } + + if (name1->type == HNT_UNSPEC || name2->type == HNT_UNSPEC) + { + return -1; + } + + size_t len1 = 0, len2 = 0; + + u8 *buffer11, *buffer12, *buffer21, *buffer22; + + switch (name1->type) + { + case HNT_CONTIGUOUS_V4: + buffer11 = name1->buffer; + buffer12 = name1->buffer + IPV4_ADDR_LEN; + len1 = IPV4_ADDR_LEN; + break; + case HNT_CONTIGUOUS_V6: + buffer11 = name1->buffer; + buffer12 = name1->buffer + IPV6_ADDR_LEN; + len1 = IPV6_ADDR_LEN; + break; + case HNT_IOV_V4: + buffer11 = name1->iov.buffers[0].iov_base; + buffer12 = name1->iov.buffers[1].iov_base; + len1 = IPV4_ADDR_LEN; + break; + case HNT_IOV_V6: + buffer11 = name1->iov.buffers[0].iov_base; + buffer12 = name1->iov.buffers[1].iov_base; + len1 = IPV6_ADDR_LEN; + break; + default: + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + switch (name2->type) + { + case HNT_CONTIGUOUS_V4: + buffer21 = name2->buffer; + buffer22 = name2->buffer + IPV4_ADDR_LEN; + len2 = IPV4_ADDR_LEN; + break; + case HNT_CONTIGUOUS_V6: + buffer21 = name2->buffer; + buffer22 = name2->buffer + IPV6_ADDR_LEN; + len2 = IPV6_ADDR_LEN; + break; + case HNT_IOV_V4: + buffer21 = name2->iov.buffers[0].iov_base; + buffer22 = name2->iov.buffers[1].iov_base; + len2 = IPV4_ADDR_LEN; + break; + case HNT_IOV_V6: + buffer21 = name2->iov.buffers[0].iov_base; + buffer22 = name2->iov.buffers[1].iov_base; + len2 = IPV6_ADDR_LEN; + break; + default: + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + // Sanity check + if (len1 != len2) + { + return HICN_LIB_ERROR_UNEXPECTED; + } + + int ret1 = memcmp ((u8 *) buffer11, (u8 *) buffer21, len1); + + if (!consider_segment) + { + return ret1; + } + + int ret2 = memcmp ((u8 *) buffer12, (u8 *) buffer22, HICN_SEGMENT_LEN); + + return ret1 || ret2; +} + +int +hicn_name_hash (const hicn_name_t * name, u32 * hash) +{ + switch (name->type) + { + case HNT_CONTIGUOUS_V4: + *hash = hash32 (name->buffer, HICN_V4_NAME_LEN); + break; + case HNT_CONTIGUOUS_V6: + *hash = hash32 (name->buffer, HICN_V6_NAME_LEN); + break; + case HNT_IOV_V4: + case HNT_IOV_V6: + *hash = + hash32 (name->iov.buffers[0].iov_base, name->iov.buffers[0].iov_len); + *hash = + cumulative_hash32 (name->iov.buffers[1].iov_base, + name->iov.buffers[1].iov_len, *hash); + break; + default: + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_empty (hicn_name_t * name) +{ + return name->type == HNT_UNSPEC ? HICN_LIB_ERROR_NONE : 1; +} + +int +hicn_name_copy (hicn_name_t * dst, const hicn_name_t * src) +{ + switch (src->type) + { + case HNT_CONTIGUOUS_V4: + case HNT_CONTIGUOUS_V6: + *dst = *src; + break; + case HNT_IOV_V4: + case HNT_IOV_V6: + dst->type = + src->type == HNT_IOV_V4 ? HNT_CONTIGUOUS_V4 : HNT_CONTIGUOUS_V6; + memcpy (dst->buffer, src->iov.buffers[0].iov_base, + src->iov.buffers[0].iov_len); + memcpy (dst->buffer + src->iov.buffers[0].iov_len, + src->iov.buffers[1].iov_base, src->iov.buffers[1].iov_len); + break; + default: + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_copy_to_destination (u8 * dst, const hicn_name_t * src, + bool copy_suffix) +{ + size_t length; + + switch (src->type) + { + case HNT_CONTIGUOUS_V4: + if (copy_suffix) + { + length = HICN_V4_NAME_LEN; + } + else + { + length = IPV4_ADDR_LEN; + } + memcpy (dst, src->buffer, length); + break; + case HNT_CONTIGUOUS_V6: + if (copy_suffix) + { + length = HICN_V6_NAME_LEN; + } + else + { + length = IPV6_ADDR_LEN; + } + memcpy (dst, src->buffer, length); + break; + case HNT_IOV_V4: + case HNT_IOV_V6: + memcpy (dst, src->iov.buffers[0].iov_base, src->iov.buffers[0].iov_len); + if (copy_suffix) + { + memcpy (dst + src->iov.buffers[0].iov_len, + src->iov.buffers[1].iov_base, src->iov.buffers[1].iov_len); + } + break; + default: + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_set_seq_number (hicn_name_t * name, u32 seq_number) +{ + u8 *sequence_number = NULL; + + switch (name->type) + { + case HNT_CONTIGUOUS_V6: + sequence_number = name->buffer + IPV6_ADDR_LEN; + break; + case HNT_CONTIGUOUS_V4: + sequence_number = name->buffer + IPV4_ADDR_LEN; + break; + case HNT_IOV_V6: + case HNT_IOV_V4: + sequence_number = name->iov.buffers[1].iov_base; + break; + case HNT_UNSPEC: + return HICN_LIB_ERROR_UNEXPECTED; + } + + if (sequence_number) + { + *(u32 *) sequence_number = seq_number; + } + else + { + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_to_sockaddr_address (const hicn_name_t * name, + struct sockaddr *ip_address) +{ + struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) ip_address; + struct sockaddr_in *tmp4 = (struct sockaddr_in *) ip_address; + + switch (name->type) + { + case HNT_CONTIGUOUS_V6: + tmp6->sin6_family = AF_INET6; + tmp6->sin6_scope_id = 0; + tmp6->sin6_port = DUMMY_PORT; + memcpy (&tmp6->sin6_addr, name->buffer, IPV6_ADDR_LEN); + break; + case HNT_IOV_V6: + tmp6->sin6_family = AF_INET6; + tmp6->sin6_scope_id = 0; + tmp6->sin6_port = DUMMY_PORT; + memcpy (&tmp6->sin6_addr, name->iov.buffers[0].iov_base, + name->iov.buffers[0].iov_len); + break; + case HNT_CONTIGUOUS_V4: + tmp4->sin_family = AF_INET; + tmp4->sin_port = DUMMY_PORT; + memcpy (&tmp4->sin_addr, name->buffer, IPV4_ADDR_LEN); + break; + case HNT_IOV_V4: + tmp4->sin_family = AF_INET; + tmp4->sin_port = DUMMY_PORT; + memcpy (&tmp4->sin_addr, name->iov.buffers[0].iov_base, + name->iov.buffers[0].iov_len); + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_to_ip_address (const hicn_name_t * name, ip_address_t * ip_address) +{ + switch (name->type) + { + case HNT_CONTIGUOUS_V6: + memcpy (&ip_address->buffer, name->buffer, IPV6_ADDR_LEN); + ip_address->family = AF_INET6; + break; + case HNT_IOV_V6: + memcpy (&ip_address->buffer, name->iov.buffers[0].iov_base, + name->iov.buffers[0].iov_len); + ip_address->family = AF_INET6; + break; + case HNT_CONTIGUOUS_V4: + memcpy (&ip_address->buffer, name->buffer, IPV4_ADDR_LEN); + ip_address->family = AF_INET; + break; + case HNT_IOV_V4: + memcpy (&ip_address->buffer, name->iov.buffers[0].iov_base, + name->iov.buffers[0].iov_len); + ip_address->family = AF_INET; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_get_seq_number (const hicn_name_t * name, u32 * seq_number) +{ + const u8 *sequence_number = NULL; + + switch (name->type) + { + case HNT_CONTIGUOUS_V6: + sequence_number = name->buffer + IPV6_ADDR_LEN; + break; + case HNT_CONTIGUOUS_V4: + sequence_number = name->buffer + IPV4_ADDR_LEN; + break; + case HNT_IOV_V6: + case HNT_IOV_V4: + sequence_number = name->iov.buffers[1].iov_base; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + if (sequence_number) + { + *seq_number = *(u32 *) sequence_number; + } + else + { + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_name_ntop (const hicn_name_t * src, char *dst, size_t len) +{ + int offset; + const char *rc; + void *seg_number = NULL; + + switch (src->type) + { + case HNT_CONTIGUOUS_V6: + rc = inet_ntop (AF_INET6, src->buffer, dst, len); + seg_number = (u8 *) src->buffer + IPV6_ADDR_LEN; + break; + case HNT_CONTIGUOUS_V4: + rc = inet_ntop (AF_INET, src->buffer, dst, len); + seg_number = (u8 *) src->buffer + IPV4_ADDR_LEN; + break; + case HNT_IOV_V6: + rc = inet_ntop (AF_INET6, src->iov.buffers[0].iov_base, dst, len); + seg_number = src->iov.buffers[1].iov_base; + break; + case HNT_IOV_V4: + rc = inet_ntop (AF_INET, src->iov.buffers[0].iov_base, dst, len); + seg_number = src->iov.buffers[1].iov_base; + break; + default: + return HICN_LIB_ERROR_NOT_IMPLEMENTED; + } + + if (!rc) + { + goto ERR; + } + + offset = strlen (dst); + dst[offset] = '|'; + + sprintf (dst + offset + 1, "%lu", (unsigned long) (*(u32 *) seg_number)); + + return HICN_LIB_ERROR_NONE; + +ERR: + return HICN_LIB_ERROR_UNSPECIFIED; +} + +int +hicn_name_pton (const char *src, hicn_name_t * dst) +{ + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +} + +int +hicn_name_get_family (const hicn_name_t * name, int *family) +{ + switch (name->type) + { + case HNT_CONTIGUOUS_V6: + case HNT_IOV_V6: + *family = AF_INET6; + break; + case HNT_CONTIGUOUS_V4: + case HNT_IOV_V4: + *family = AF_INET; + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + +int +hicn_prefix_create_from_ip_address (const ip_address_t * ip_address, + hicn_prefix_t * prefix) +{ + switch (ip_address->family) + { + case AF_INET: + prefix->name.ip4.as_u32 = ip_address->as_u32[0]; + break; + case AF_INET6: + prefix->name.ip6.as_u64[0] = ip_address->as_u64[0]; + prefix->name.ip6.as_u64[1] = ip_address->as_u64[1]; + break; + default: + return HICN_LIB_ERROR_INVALID_IP_ADDRESS; + } + prefix->len = ip_address->prefix_len; + + return HICN_LIB_ERROR_NONE; +} + +#endif /* ! HICN_VPP_PLUGIN */ + +/******** + * IP + */ + +inline int +ip_address_len (const ip_address_t * ip_address) +{ + return (ip_address->family == AF_INET6) ? IPV6_ADDR_LEN : + (ip_address->family == AF_INET) ? IPV4_ADDR_LEN : 0; +} + +bool +ip_address_empty (const ip_address_t * ip_address) +{ + return ip_address->prefix_len == 0; +} + +int +hicn_ip_ntop (const ip_address_t * ip_address, char *dst, const size_t len) +{ + const char *rc; + + rc = inet_ntop (ip_address->family, ip_address->buffer, dst, len); + if (!rc) + { + printf ("error ntop: %d %s\n", errno, strerror (errno)); + return HICN_LIB_ERROR_INVALID_IP_ADDRESS; + } + + return HICN_LIB_ERROR_NONE; +} + +/* + * Parse ip addresses in presentation format, or prefixes (in bits, separated by a slash) + */ +int +hicn_ip_pton (const char *ip_address_str, ip_address_t * ip_address) +{ + int pton_fd; + char *p; + char *eptr; + u32 dst_len; + char *addr = strdup (ip_address_str); + + p = strchr (addr, '/'); + if (!p) + { + dst_len = 0; // until we get the ip address family + } + else + { + dst_len = strtoul (p + 1, &eptr, 10); + *p = 0; + } + + ip_address->family = get_addr_family (addr); + + switch (ip_address->family) + { + case AF_INET6: + if (dst_len > IPV6_ADDR_LEN_BITS) + goto ERR; + pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer); + ip_address->prefix_len = dst_len ? : IPV6_ADDR_LEN_BITS; + break; + case AF_INET: + if (dst_len > IPV4_ADDR_LEN_BITS) + goto ERR; + pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer); + ip_address->prefix_len = dst_len ? : IPV4_ADDR_LEN_BITS; + break; + default: + goto ERR; + } + + // 0 = not in presentation format + // < 0 = other error (use perror) + if (pton_fd <= 0) + { + goto ERR; + } + + return HICN_LIB_ERROR_NONE; +ERR: + free (addr); + return HICN_LIB_ERROR_INVALID_IP_ADDRESS; +} + +int +hicn_ip_to_sockaddr_address (const ip_address_t * ip_address, + struct sockaddr *sockaddr_address) +{ + struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address; + struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address; + + switch (ip_address->family) + { + case AF_INET6: + tmp6->sin6_family = AF_INET6; + tmp6->sin6_port = DUMMY_PORT; + tmp6->sin6_scope_id = 0; + memcpy (&tmp6->sin6_addr, ip_address->buffer, IPV6_ADDR_LEN); + break; + case AF_INET: + tmp4->sin_family = AF_INET; + tmp4->sin_port = DUMMY_PORT; + memcpy (&tmp4->sin_addr, ip_address->buffer, IPV4_ADDR_LEN); + break; + default: + return HICN_LIB_ERROR_UNEXPECTED; + } + + return HICN_LIB_ERROR_NONE; +} + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/name.h b/lib/src/name.h new file mode 100755 index 000000000..0a55fedc6 --- /dev/null +++ b/lib/src/name.h @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file name.h + * @brief hICN name helpers. + * + * The purpose of the file is to offer an efficient, platform- and protocol- + * independent way to manipulate hICN names. + */ + +#ifndef HICN_NAME_H +#define HICN_NAME_H + +#include <stdbool.h> +#include <netinet/in.h> // struct sockadd + +#include "common.h" + +/****************************************************************************** + * IP address helpers + ******************************************************************************/ + +/* Presentation format */ +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 +//#define INET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN + +/* Address size */ +#define bytes_to_bits(x) (x * 8) +#define IPV6_ADDR_LEN 16 /* bytes */ +#define IPV4_ADDR_LEN 4 /* bytes */ +#define IPV6_ADDR_LEN_BITS bytes_to_bits(IPV6_ADDR_LEN) +#define IPV4_ADDR_LEN_BITS bytes_to_bits(IPV4_ADDR_LEN) + +#define IP_MAX_ADDR_LEN IPV6_ADDR_LEN +#define TCP_SEQNO_LEN 4 /* bytes */ + +typedef struct +{ + union + { + u8 buffer[IP_MAX_ADDR_LEN]; + u8 as_u8[IP_MAX_ADDR_LEN]; + u16 as_u16[IP_MAX_ADDR_LEN >> 1]; + u32 as_u32[IP_MAX_ADDR_LEN >> 2]; + u64 as_u64[IP_MAX_ADDR_LEN >> 3]; + ip4_address_t as_ip4; + ip6_address_t as_ip6; + }; + int family; + unsigned short prefix_len; +} ip_address_t; + +int ip_address_len (const ip_address_t * ip_address); +bool ip_address_empty (const ip_address_t * ip_address); + +int hicn_ip_ntop (const ip_address_t * ip_address, char *dst, + const size_t len); +int hicn_ip_pton (const char *ip_address_str, ip_address_t * ip_address); +int hicn_ip_to_sockaddr_address (const ip_address_t * ip_address, + struct sockaddr *sockaddr_address); + +/****************************************************************************** + * hICN names + ******************************************************************************/ + +#define HICN_V4_PREFIX_LEN IPV4_ADDR_LEN +#define HICN_V6_PREFIX_LEN IPV6_ADDR_LEN +#define HICN_SEGMENT_LEN TCP_SEQNO_LEN +#define HICN_V6_NAME_LEN (HICN_V6_PREFIX_LEN + HICN_SEGMENT_LEN) /* 20 bytes */ +#define HICN_V4_NAME_LEN (HICN_V4_PREFIX_LEN + HICN_SEGMENT_LEN) /* 8 bytes */ + +/* Prefix */ + +typedef u32 hicn_name_suffix_t; + +typedef struct +{ + ip46_address_t name; + u8 len; +} hicn_prefix_t; + +/* + * Name + * + * A name is a prefix + a segment name (suffix) + */ + +typedef union +{ + struct + { + union + { + u32 prefix; + u8 prefix_as_u8[4]; + ip4_address_t prefix_as_ip4; + }; + hicn_name_suffix_t suffix; + }; + u8 buffer[HICN_V4_NAME_LEN]; +} hicn_v4_name_t; + +typedef union +{ + struct + { + union + { + u64 prefix[2]; + u8 prefix_as_u8[16]; + ip6_address_t prefix_as_ip6; + }; + hicn_name_suffix_t suffix; + }; + u8 buffer[HICN_V6_NAME_LEN]; +} hicn_v6_name_t; + +typedef struct +{ + u8 buffer[0]; +} hicn_v46_name_t; + +#ifndef HICN_VPP_PLUGIN +#define HICN_NAME_COMPONENT_SIZE 2 + +typedef struct +{ + struct iovec buffers[HICN_NAME_COMPONENT_SIZE]; +} hicn_iov_name_t; + +#define UNSPEC 1 << 0 +#define HNT_CONTIGUOUS 1 << 1 +#define HNT_IOV 1 << 2 +#define HNT_INET 1 << 3 +#define HNT_INET6 1 << 4 + +typedef enum +{ + HNT_UNSPEC = UNSPEC, + HNT_CONTIGUOUS_V4 = HNT_CONTIGUOUS | HNT_INET, + HNT_CONTIGUOUS_V6 = HNT_CONTIGUOUS | HNT_INET6, + HNT_IOV_V4 = HNT_IOV | HNT_INET, + HNT_IOV_V6 = HNT_IOV | HNT_INET6, +} hicn_name_type_t; +#endif /* HICN_VPP_PLUGIN */ + +typedef struct +{ +#ifndef HICN_VPP_PLUGIN + hicn_name_type_t type; + u8 len; +#endif /* HICN_VPP_PLUGIN */ + union + { + hicn_v4_name_t ip4; + hicn_v6_name_t ip6; + ip46_address_t ip46; +#ifndef HICN_VPP_PLUGIN + hicn_iov_name_t iov; + u8 buffer[0]; +#endif /* HICN_VPP_PLUGIN */ + }; +} hicn_name_t; + +#ifndef HICN_VPP_PLUGIN +#define _is_unspec(name) ((name->type & UNSPEC)) +#define _is_contiguous(name) ((name->type & HNT_CONTIGUOUS) >> 1) +#define _is_iov(name) ((name->type & HNT_IOV) >> 2) +#define _is_inet4(name) ((name->type & HNT_INET) >> 3) +#define _is_inet6(name) ((name->type & HNT_INET6) >> 4) +#endif /* HICN_VPP_PLUGIN */ + +/** + * @brief Create an hICN name from IP address in presentation format + * @param [in] ip_address - IP address + * @param [in] id - Segment identifier + * @param [out] Resulting hICN name + * @return hICN error code + */ +int hicn_name_create (const char *ip_address, u32 id, hicn_name_t * name); + +/** + * @brief Create an hICN name from IP address + * @param [in] ip_address - IP address + * @param [in] id Segment - identifier + * @param [out] Resulting - hICN name + * @return hICN error code + */ +int hicn_name_create_from_ip_address (const ip_address_t * ip_address, u32 id, + hicn_name_t * name); + +/** + * @brief Returns the length of an hICN name + * @param [in] name - hICN name + * @return Name length + */ +u8 hicn_name_get_length (const hicn_name_t * name); + +/** + * @brief Compare two hICN names + * @param [in] name_1 - First name to compare + * @param [in] name_2 - Second name to compare + * @param [in] consider_segment - Flag indicating whether the segment part has to be + * considered + * @return An integer less than, equal to, or greater than zero if name_1 is + * found, respectively, to be lest than, to match, or be greater than name_2 + * based on numeric order. + */ +int hicn_name_compare (const hicn_name_t * name_1, const hicn_name_t * name_2, + bool consider_segment); + +/** + * @brief Provides a 32-bit hash of an hICN name + * @param [in] name - Name to hash + * @param [out] hash - Resulting hash + * @return hICN error code + */ +int hicn_name_hash (const hicn_name_t * name, u32 * hash); + +/** + * @brief Test whether an hICN name is empty + * @param [in] name - Name to test + * @return 0 if the name is empty, any other value otherwise (implementation + * returns 1) + */ +int hicn_name_empty (hicn_name_t * name); + +/** + * @brief Copy an hICN name + * @param [out] dst - Destination name + * @param [in] src - Source name to copy + * @return hICN error code + */ +int hicn_name_copy (hicn_name_t * dst, const hicn_name_t * src); + +/** + * @brief Copy an hICN name to a buffer + * @param [out] dst - Destination buffer + * @param [in] src - Source name to copy + * @param [in] copy_suffix - Flag indicating whether the suffix has to be + * considered + */ +int hicn_name_copy_to_destination (u8 * dst, const hicn_name_t * src, + bool copy_suffix); + +/** + * @brief Sets the segment part of an hICN name + * @param [in,out] name - hICN name to modify + * @param [in] seq_number - Segment identifier + * @return hICN error code + */ +int hicn_name_set_seq_number (hicn_name_t * name, u32 seq_number); + +/** + * @brief Retrieves the segment part of an hICN name + * @param [in,out] name - hICN name + * @param [in] seq_number - Segment identifier + * @return hICN error code + */ +int hicn_name_get_seq_number (const hicn_name_t * name, u32 * seq_number); + +/** + * @brief Convert an hICN name to a socket address + * @param [in] name - Name to convert + * @param [out] ip_address - Resulting socket address + * @return hICN error code + */ +int hicn_name_to_sockaddr_address (const hicn_name_t * name, + struct sockaddr *ip_address); + +/** + * @brief Convert an hICN name to an IP address + * @param [in] name - Name to convert + * @param [out] ip_address - Resulting IP address + * @return hICN error code + */ +int hicn_name_to_ip_address (const hicn_name_t * name, + ip_address_t * ip_address); + +/** + * @brief Convert an hICN name to presentation format + * @param [in] src - Name to convert + * @param [out] dst - Buffer to receive the name in presentation format + * @param [in] len - Number of bytes available in the buffer + * @return hICN error code + */ +int hicn_name_ntop (const hicn_name_t * src, char *dst, size_t len); + +/** + * @brief Convert an hICN name from presentation format + * @param [in] src - Name in presentation format to parse + * @param [out] dst - Resulting name + * @return hICN error code + */ +int hicn_name_pton (const char *src, hicn_name_t * dst); + +/** + * @brief Returns the IP address family of an hICN name + * @param [in] name - Name to lookup + * @param [out] family - Resulting IP address family (AF_INET or AF_INET6) + * @return hICN error code + */ +int hicn_name_get_family (const hicn_name_t * name, int *family); + +/** + * @brief Creates an hICN prefix from an IP address + * @param [in] ip_address - Input IP address + * @param [out] prefix - Resulting prefix + * @return hICN error code + */ +int hicn_prefix_create_from_ip_address (const ip_address_t * ip_address, + hicn_prefix_t * prefix); + +#endif /* HICN_NAME_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/ops.c b/lib/src/ops.c new file mode 100755 index 000000000..ad45a13a5 --- /dev/null +++ b/lib/src/ops.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file ops.c + * @brief Initializers for protocol-independent packet operations + */ + +#include <netinet/in.h> +#include <stdlib.h> +#include "ops.h" + +#include "header.h" + +extern const hicn_ops_t hicn_ops_ipv4; +extern const hicn_ops_t hicn_ops_icmp; +extern const hicn_ops_t hicn_ops_tcp; +extern const hicn_ops_t hicn_ops_ipv6; +extern const hicn_ops_t hicn_ops_ah; + +/* Declare empty operations (terminates recursion on protocol layers) */ +DECLARE_init_packet_header (none, NONE); +DECLARE_get_interest_locator (none, NONE); +DECLARE_set_interest_locator (none, NONE); +DECLARE_get_interest_name (none, NONE); +DECLARE_set_interest_name (none, NONE); +DECLARE_get_interest_name_suffix (none, NONE); +DECLARE_set_interest_name_suffix (none, NONE); +DECLARE_reset_interest_for_hash (none, NONE); +DECLARE_get_data_locator (none, NONE); +DECLARE_set_data_locator (none, NONE); +DECLARE_get_data_name (none, NONE); +DECLARE_set_data_name (none, NONE); +DECLARE_get_data_name_suffix (none, NONE); +DECLARE_set_data_name_suffix (none, NONE); +DECLARE_get_data_pathlabel (none, NONE); +DECLARE_set_data_pathlabel (none, NONE); +DECLARE_update_data_pathlabel (none, NONE); +DECLARE_reset_data_for_hash (none, NONE); +DECLARE_get_lifetime (none, NONE); +DECLARE_set_lifetime (none, NONE); +DECLARE_update_checksums (none, NONE); +DECLARE_verify_checksums (none, NONE); +DECLARE_rewrite_interest (none, NONE); +DECLARE_rewrite_data (none, NONE); +DECLARE_get_length (none, NONE); +DECLARE_get_header_length (none, NONE); +DECLARE_get_current_header_length (none, NONE); +DECLARE_get_payload_length (none, NONE); +DECLARE_set_payload_length (none, NONE); +DECLARE_get_signature_size (none, NONE); +DECLARE_set_signature_size (none, NONE); +DECLARE_set_signature_timestamp (none, NONE); +DECLARE_get_signature_timestamp (none, NONE); +DECLARE_set_validation_algorithm (none, NONE); +DECLARE_get_validation_algorithm (none, NONE); +DECLARE_set_key_id (none, NONE); +DECLARE_get_key_id (none, NONE); +DECLARE_HICN_OPS (none); + +/** + * @brief Virtual function table for packet operations + * NOTE: protocol numbers have to be kept in order + */ +const hicn_ops_t *const hicn_ops_vft[] = { + /* 0 */ [IPPROTO_IP] = &hicn_ops_ipv4, + /* 1 */ [IPPROTO_ICMP] = &hicn_ops_icmp, + /* 6 */ [IPPROTO_TCP] = &hicn_ops_tcp, + /* 41 */ [IPPROTO_IPV6] = &hicn_ops_ipv6, + /* 51 */ [IPPROTO_AH] = &hicn_ops_ah, + /* 58 */ [IPPROTO_ICMPV6] = &hicn_ops_icmp, + [IPPROTO_NONE] = &hicn_ops_none, +}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/ops.h b/lib/src/ops.h new file mode 100755 index 000000000..d56e6ae4a --- /dev/null +++ b/lib/src/ops.h @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file base.h + * @brief Protocol-independent packet operations + */ + +#ifndef HICN_OPS_H +#define HICN_OPS_H + +#include <stdlib.h> + +#include "error.h" +#include "header.h" +#include "name.h" + +/* + * hICN operations on packets + * + * All prototypes take an hicn_type_t parameter as their first argument, as this + * decides the sequence of protocols that are being used by the different + * operations. + */ + +typedef struct hicn_ops_s +{ + /** Protocol name */ + const char *name; + + /** + * @brief Initialize the headers of the hicn packet + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the packet + */ + int (*init_packet_header) (hicn_type_t type, hicn_protocol_t * h); + + /** + * @brief Retrieves an Interest locator + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest packet + * @param [out] ip_address - Retrieved locator + * @return hICN error code + */ + int (*get_interest_locator) (hicn_type_t type, const hicn_protocol_t * h, + ip46_address_t * ip_address); + + /** + * @brief Sets an Interest locator + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest packet + * @param [in] ip_address - Locator to set + * @return hICN error code + */ + int (*set_interest_locator) (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * ip_address); + + /** + * @brief Retrieves an Interest name + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest packet + * @param [out] name - Retrieved name + * @return hICN error code + */ + int (*get_interest_name) (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_t * name); + + /** + * @brief Sets an Interest name + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest packet + * @param [in] name - Name to set + * @return hICN error code + */ + int (*set_interest_name) (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_t * name); + + /** + * @brief Retrieves an Interest name suffix + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest packet + * @param [out] suffix - Retrieved name suffix + * @return hICN error code + */ + int (*get_interest_name_suffix) (hicn_type_t type, + const hicn_protocol_t * h, + hicn_name_suffix_t * suffix); + + /** + * @brief Sets an Interest name suffix + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest packet + * @param [in] suffix - Name suffix to set + * @return hICN error code + */ + int (*set_interest_name_suffix) (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix); + + /** + * @brief Clear the necessary Interest fields in order to hash it + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest packet + * @return hICN error code + */ + int (*reset_interest_for_hash) (hicn_type_t type, hicn_protocol_t * h); + + /** + * @brief Retrieves a Data locator + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Data packet + * @param [out] ip_address - Retrieved locator + * @return hICN error code + */ + int (*get_data_locator) (hicn_type_t type, const hicn_protocol_t * h, + ip46_address_t * ip_address); + + /** + * @brief Sets a Data locator + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Data packet + * @param [in] ip_address - Locator to set + * @return hICN error code + */ + int (*set_data_locator) (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * ip_address); + + /** + * @brief Retrieves a Data name + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Data packet + * @param [out] name - Retrieved name + * @return hICN error code + */ + int (*get_data_name) (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_t * name); + + /** + * @brief Sets a Data name + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Data packet + * @param [in] name - Name to set + * @return hICN error code + */ + int (*set_data_name) (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_t * name); + + /** + * @brief Retrieves a Data name suffix + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Data packet + * @param [out] suffix - Retrieved name suffix + * @return hICN error code + */ + int (*get_data_name_suffix) (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_suffix_t * suffix); + + /** + * @brief Sets a Data name suffix + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Data packet + * @param [in] suffix - Name suffix to set + * @return hICN error code + */ + int (*set_data_name_suffix) (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix); + + /** + * @brief Retrieves a Data pathlabel + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Data packet + * @param [out] pathlabel - Retrieved pathlabel + * @return hICN error code + */ + int (*get_data_pathlabel) (hicn_type_t type, const hicn_protocol_t * h, + u32 * pathlabel); + + /** + * @brief Sets a Data pathlabel + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Data packet + * @param [in] pathlabel - Pathlabel to set + * @return hICN error code + */ + int (*set_data_pathlabel) (hicn_type_t type, hicn_protocol_t * h, + const u32 pathlabel); + + /** + * @brief Update a Data pathlabel with a new face identifier + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Data packet + * @param [in] pathlabel - Face identifier used to update pathlabel + * @return hICN error code + */ + int (*update_data_pathlabel) (hicn_type_t type, hicn_protocol_t * h, + const hicn_faceid_t face_id); + + /** + * @brief Clear the necessary Data fields in order to hash it + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Data packet + * @return hICN error code + */ + int (*reset_data_for_hash) (hicn_type_t type, hicn_protocol_t * h); + + /** + * @brief Retrieves an Interest or Data lifetime + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest or Data packet + * @param [out] pathlabel - Retrieved lifetime + * @return hICN error code + */ + int (*get_lifetime) (hicn_type_t type, const hicn_protocol_t * h, + hicn_lifetime_t * lifetime); + + /** + * @brief Sets an Interest or Data lifetime + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [in] pathlabel - Lifetime to set + * @return hICN error code + */ + int (*set_lifetime) (hicn_type_t type, hicn_protocol_t * h, + const hicn_lifetime_t lifetime); + + /** + * @brief Update all checksums in packet headers + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the packet + * @param [in] partial_csum - Partial checksum (set to 0, used internally to + * carry intermediate values from IP pseudo-header) + * @param [in] payload_length - Payload length (can be set to 0, retrieved + * and used internally to carry payload length across protocol headers) + * @return hICN error code + */ + int (*update_checksums) (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length); + + /** + * @brief Validate all checksums in packet headers + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the packet + * @param [in] partial_csum - Partial checksum (set to 0, used internally to + * carry intermediate values from IP pseudo-header) + * @param [in] payload_length - Payload length (can be set to 0, retrieved + * and used internally to carry payload length across protocol headers) + * @return hICN error code + */ + int (*verify_checksums) (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length); + + /** + * @brief Rewrite an Interest packet header (locator) + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest packet + * @param [in] addr_new - New locator + * @param [in] addr_old - Old locator (set to NULL, used internally to + * compute incremental checksums) + * @return hICN error code + */ + int (*rewrite_interest) (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, + ip46_address_t * addr_old); + + /** + * @brief Rewrite a Data packet header (locator + pathlabel) + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Data packet + * @param [in] addr_new - New locator + * @param [in] addr_old - Old locator (set to NULL, used internally to + * compute incremental checksums) + * @param [in] face_id - Face identifier used to update pathlabel + * @return hICN error code + */ + int (*rewrite_data) (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, + ip46_address_t * addr_old, + const hicn_faceid_t face_id); + + /** + * @brief Return the packet length + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the packet + * @parma [out] length - Returned packet length + * @return hICN error code + */ + int (*get_length) (hicn_type_t type, const hicn_protocol_t * h, + size_t * length); + + /** + * @brief Return the current packet header length + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the packet + * @parma [out] header_length - Returned packet current header length + * @return hICN error code + */ + int (*get_current_header_length) (hicn_type_t type, + const hicn_protocol_t * h, + size_t * header_length); + + /** + * @brief Return the packet header length + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the packet + * @parma [out] header_length - Returned packet header length + * @return hICN error code + */ + int (*get_header_length) (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length); + + /** + * @brief Return the packet payload length + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the packet + * @parma [out] payload_length - Returned packet payload length + * @return hICN error code + */ + int (*get_payload_length) (hicn_type_t type, const hicn_protocol_t * h, + size_t * payload_length); + + /** + * @brief Sets the packet paylaod length + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the packet + * @parma [out] payload_length - Payload length to set + * @return hICN error code + */ + int (*set_payload_length) (hicn_type_t type, hicn_protocol_t * h, + size_t payload_length); + + /** + * @brief Retrieves an Interest or Data signature size + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest or Data packet + * @param [out] signature_size - Retrieved signature size + * @return hICN error code + */ + int (*get_signature_size) (hicn_type_t type, const hicn_protocol_t * h, + size_t * signature_size); + + /** + * @brief Sets an Interest or Data signature size + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [in] signature_size - Signature size to set + * @return hICN error code + */ + int (*set_signature_size) (hicn_type_t type, hicn_protocol_t * h, + size_t signature_size); + + /** + * @brief Sets the signature timestamp + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [in] signature_timestamp - Signature timestamp to set + * @return hICN error code + */ + int (*set_signature_timestamp) (hicn_type_t type, hicn_protocol_t * h, + uint64_t signature_timestamp); + + /** + * @brief Gets the signature timestamp + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [out] signature_timestamp - Retrieved signature timestamp + * @return hICN error code + */ + int (*get_signature_timestamp) (hicn_type_t type, const hicn_protocol_t * h, + uint64_t *signature_timestamp); + + /** + * @brief Sets the signature validation algorithm + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [in] validation_algorithm - Validation algorithm enumeration + * @return hICN error code + */ + int (*set_validation_algorithm) (hicn_type_t type, hicn_protocol_t * h, + uint8_t validation_algorithm); + + /** + * @brief Gets the signature validation algorithm + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [out] validation_algorithm - Retrieved validation_algorithm + * @return hICN error code + */ + int (*get_validation_algorithm) (hicn_type_t type, const hicn_protocol_t * h, + uint8_t *validation_algorithm); + + /** + * @brief Sets the key id + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [in] key_id - Key id first byte address + * @return hICN error code + */ + int (*set_key_id) (hicn_type_t type, hicn_protocol_t * h, + uint8_t *key_id); + + /** + * @brief Gets the key id + * @param [in] type - hICN packet type + * @param [in,out] h - Buffer holding the Interest or Data packet + * @param [out] key_id - Retrieved key id first byte address + * @return hICN error code + */ + int (*get_key_id) (hicn_type_t type, hicn_protocol_t * h, + uint8_t **key_id, uint8_t *key_id_size); + +} hicn_ops_t; + +#define DECLARE_HICN_OPS(protocol) \ + const hicn_ops_t hicn_ops_ ## protocol = { \ + .init_packet_header = protocol ## _init_packet_header, \ + .get_interest_locator = protocol ## _get_interest_locator, \ + .set_interest_locator = protocol ## _set_interest_locator, \ + .get_interest_name = protocol ## _get_interest_name, \ + .set_interest_name = protocol ## _set_interest_name, \ + .get_interest_name_suffix = protocol ## _get_interest_name_suffix, \ + .set_interest_name_suffix = protocol ## _set_interest_name_suffix, \ + .reset_interest_for_hash = protocol ## _reset_interest_for_hash, \ + .get_data_locator = protocol ## _get_data_locator, \ + .set_data_locator = protocol ## _set_data_locator, \ + .get_data_name = protocol ## _get_data_name, \ + .set_data_name = protocol ## _set_data_name, \ + .get_data_name_suffix = protocol ## _get_data_name_suffix, \ + .set_data_name_suffix = protocol ## _set_data_name_suffix, \ + .get_data_pathlabel = protocol ## _get_data_pathlabel, \ + .set_data_pathlabel = protocol ## _set_data_pathlabel, \ + .update_data_pathlabel = protocol ## _update_data_pathlabel, \ + .reset_data_for_hash = protocol ## _reset_data_for_hash, \ + .get_lifetime = protocol ## _get_lifetime, \ + .set_lifetime = protocol ## _set_lifetime, \ + .update_checksums = protocol ## _update_checksums, \ + .verify_checksums = protocol ## _verify_checksums, \ + .rewrite_interest = protocol ## _rewrite_interest, \ + .rewrite_data = protocol ## _rewrite_data, \ + .get_length = protocol ## _get_length, \ + .get_current_header_length= protocol ## _get_current_header_length, \ + .get_header_length = protocol ## _get_header_length, \ + .get_payload_length = protocol ## _get_payload_length, \ + .set_payload_length = protocol ## _set_payload_length, \ + .get_signature_size = protocol ## _get_signature_size, \ + .set_signature_size = protocol ## _set_signature_size, \ + .set_signature_timestamp = protocol ## _set_signature_timestamp, \ + .get_signature_timestamp = protocol ## _get_signature_timestamp, \ + .set_validation_algorithm = protocol ## _set_validation_algorithm, \ + .get_validation_algorithm = protocol ## _get_validation_algorithm, \ + .set_key_id = protocol ## _set_key_id, \ + .get_key_id = protocol ## _get_key_id, \ + } + +/** + * @brief Protocol-independent packet operations VFT + * NOTE: The following declarations should be kept in order + */ +extern const hicn_ops_t *const hicn_ops_vft[]; + +/* + * Helpers for writing recursive protocol operations on packet headers + * + * NOTE : we cannot use a shift operation as IPPROTO_NONE != 0 (and 0 is IPv4...) + */ +always_inline hicn_type_t +TYPE_POP (hicn_type_t type) +{ + return (hicn_type_t) + { + { + .l1 = type.l2,.l2 = type.l3,.l3 = type.l4,.l4 = IPPROTO_NONE,} + }; +} + +always_inline hicn_protocol_t * +PAYLOAD (hicn_type_t type, const hicn_protocol_t * h) +{ + size_t header_length; + int rc = hicn_ops_vft[type.l1]->get_current_header_length (type, h, + &header_length); + if (rc < 0) + return NULL; + return (hicn_protocol_t *) ((u8 *) h + header_length); +} + +#define CHILD_OPS(f, type, h, ...) (hicn_ops_vft[type.l2]->f(TYPE_POP(type), PAYLOAD(type, h), ## __VA_ARGS__)) + +/** Shortcuts to entry points in VFT */ +#define HICN_OPS4 hicn_ops_vft[IPPROTO_IP] +#define HICN_OPS6 hicn_ops_vft[IPPROTO_IPV6] + +/* Helpers for simple declarations */ + +#define DECLARE_init_packet_header(protocol, error) \ + int protocol ## _init_packet_header(hicn_type_t type, hicn_protocol_t * h) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_interest_locator(protocol, error) \ + int protocol ## _get_interest_locator(hicn_type_t type, const hicn_protocol_t * h, ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_interest_locator(protocol, error) \ + int protocol ## _set_interest_locator(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_interest_name(protocol, error) \ + int protocol ## _get_interest_name(hicn_type_t type, const hicn_protocol_t * h, hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_interest_name(protocol, error) \ + int protocol ## _set_interest_name(hicn_type_t type, hicn_protocol_t * h, const hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_interest_name_suffix(protocol, error) \ + int protocol ## _get_interest_name_suffix(hicn_type_t type, const hicn_protocol_t * h, hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_interest_name_suffix(protocol, error) \ + int protocol ## _set_interest_name_suffix(hicn_type_t type, hicn_protocol_t * h, const hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_reset_interest_for_hash(protocol, error) \ + int protocol ## _reset_interest_for_hash(hicn_type_t type, hicn_protocol_t * h) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_data_locator(protocol, error) \ + int protocol ## _get_data_locator(hicn_type_t type, const hicn_protocol_t * h, ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_data_locator(protocol, error) \ + int protocol ## _set_data_locator(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_data_name(protocol, error) \ + int protocol ## _get_data_name(hicn_type_t type, const hicn_protocol_t * h, hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_data_name(protocol, error) \ + int protocol ## _set_data_name(hicn_type_t type, hicn_protocol_t * h, const hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_data_name_suffix(protocol, error) \ + int protocol ## _get_data_name_suffix(hicn_type_t type, const hicn_protocol_t * h, hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_data_name_suffix(protocol, error) \ + int protocol ## _set_data_name_suffix(hicn_type_t type, hicn_protocol_t * h, const hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_data_pathlabel(protocol, error) \ + int protocol ## _get_data_pathlabel(hicn_type_t type, const hicn_protocol_t * h, u32 * pathlabel) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_data_pathlabel(protocol, error) \ + int protocol ## _set_data_pathlabel(hicn_type_t type, hicn_protocol_t * h, const u32 pathlabel) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_update_data_pathlabel(protocol, error) \ + int protocol ## _update_data_pathlabel(hicn_type_t type, hicn_protocol_t * h, const hicn_faceid_t face_id) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_reset_data_for_hash(protocol, error) \ + int protocol ## _reset_data_for_hash(hicn_type_t type, hicn_protocol_t * h) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_lifetime(protocol, error) \ + int protocol ## _get_lifetime(hicn_type_t type, const hicn_protocol_t * h, hicn_lifetime_t * lifetime) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_lifetime(protocol, error) \ + int protocol ## _set_lifetime(hicn_type_t type, hicn_protocol_t * h, const hicn_lifetime_t lifetime) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_update_checksums(protocol, error) \ + int protocol ## _update_checksums(hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, size_t payload_length) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_verify_checksums(protocol, error) \ + int protocol ## _verify_checksums(hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, size_t payload_length) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_rewrite_interest(protocol, error) \ + int protocol ## _rewrite_interest(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * addr_new, ip46_address_t * addr_old) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_rewrite_data(protocol, error) \ + int protocol ## _rewrite_data(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * addr_new, ip46_address_t * addr_old, const hicn_faceid_t face_id) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_length(protocol, error) \ + int protocol ## _get_length(hicn_type_t type, const hicn_protocol_t * h, size_t * length) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_current_header_length(protocol, error) \ + int protocol ## _get_current_header_length(hicn_type_t type, const hicn_protocol_t * h, size_t * header_length) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_header_length(protocol, error) \ + int protocol ## _get_header_length(hicn_type_t type, const hicn_protocol_t * h, size_t * header_length) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_payload_length(protocol, error) \ + int protocol ## _get_payload_length(hicn_type_t type, const hicn_protocol_t * h, size_t * payload_length) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_payload_length(protocol, error) \ + int protocol ## _set_payload_length(hicn_type_t type, hicn_protocol_t * h, size_t payload_length) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_signature_size(protocol, error) \ + int protocol ## _get_signature_size(hicn_type_t type, const hicn_protocol_t * h, size_t * signature_size) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_signature_size(protocol, error) \ + int protocol ## _set_signature_size(hicn_type_t type, hicn_protocol_t * h, size_t signature_size) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_signature_timestamp(protocol, error) \ + int protocol ## _set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h, uint64_t signature_timestamp) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_signature_timestamp(protocol, error) \ + int protocol ## _get_signature_timestamp(hicn_type_t type, const hicn_protocol_t * h, uint64_t * signature_timestamp) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_validation_algorithm(protocol, error) \ + int protocol ## _set_validation_algorithm(hicn_type_t type, hicn_protocol_t * h, uint8_t validation_algorithm) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_validation_algorithm(protocol, error) \ + int protocol ## _get_validation_algorithm(hicn_type_t type, const hicn_protocol_t * h, uint8_t * validation_algorithm) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_set_key_id(protocol, error) \ + int protocol ## _set_key_id(hicn_type_t type, hicn_protocol_t * h, uint8_t * key_id) { return HICN_LIB_ERROR_ ## error ; } + +#define DECLARE_get_key_id(protocol, error) \ + int protocol ## _get_key_id(hicn_type_t type, hicn_protocol_t * h, uint8_t ** key_id, uint8_t *key_id_size) { return HICN_LIB_ERROR_ ## error ; } + +#endif /* HICN_OPS_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol.h b/lib/src/protocol.h new file mode 100755 index 000000000..a97cc99cf --- /dev/null +++ b/lib/src/protocol.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file protocol.h + * @brief Protocol header definitions + */ +#ifndef HICN_PROTOCOL_H +#define HICN_PROTOCOL_H + +#include "protocol/ah.h" +#include "protocol/ipv4.h" +#include "protocol/ipv6.h" +#include "protocol/icmp.h" +#include "protocol/icmprd.h" +#include "protocol/tcp.h" +#include "protocol/udp.h" + +typedef union +{ + _ipv4_header_t ipv4; + _ipv6_header_t ipv6; + _tcp_header_t tcp; + _udp_header_t udp; + _icmp_header_t icmp; + _icmprd_header_t icmprd; + _ah_header_t ah; + void *bytes; +} hicn_protocol_t; + +#endif /* HICN_PROTOCOL_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/ah.c b/lib/src/protocol/ah.c new file mode 100755 index 000000000..f9ddf7775 --- /dev/null +++ b/lib/src/protocol/ah.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file protocol/ah.c + * @brief hICN operations for AH header + */ + +#include <string.h> // memcpy +#include "../common.h" +#include "../error.h" +#include "../header.h" +#include "../ops.h" +#include "ah.h" + +DECLARE_get_interest_locator (ah, UNEXPECTED); +DECLARE_set_interest_locator (ah, UNEXPECTED); +DECLARE_get_interest_name (ah, UNEXPECTED); +DECLARE_set_interest_name (ah, UNEXPECTED); +DECLARE_get_interest_name_suffix (ah, UNEXPECTED); +DECLARE_set_interest_name_suffix (ah, UNEXPECTED); +DECLARE_get_data_locator (ah, UNEXPECTED); +DECLARE_set_data_locator (ah, UNEXPECTED); +DECLARE_get_data_name (ah, UNEXPECTED); +DECLARE_set_data_name (ah, UNEXPECTED); +DECLARE_get_data_name_suffix (ah, UNEXPECTED); +DECLARE_set_data_name_suffix (ah, UNEXPECTED); +DECLARE_get_data_pathlabel (ah, UNEXPECTED); +DECLARE_set_data_pathlabel (ah, UNEXPECTED); +DECLARE_update_data_pathlabel (ah, UNEXPECTED); +DECLARE_get_lifetime (ah, UNEXPECTED); +DECLARE_set_lifetime (ah, UNEXPECTED); +DECLARE_get_payload_length (ah, UNEXPECTED); +DECLARE_set_payload_length (ah, UNEXPECTED); + +int +ah_init_packet_header (hicn_type_t type, hicn_protocol_t * h) +{ + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +} + +int +ah_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + size_t signature_size; + int rc = + hicn_ops_vft[type.l1]->get_signature_size (type, h, &signature_size); + if (rc < 0) + return rc; + memset (&(h->ah.validationPayload), 0, signature_size); + return CHILD_OPS (reset_interest_for_hash, type, h); +} + +int +ah_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + size_t signature_size; + int rc = + hicn_ops_vft[type.l1]->get_signature_size (type, h, &signature_size); + if (rc < 0) + return rc; + memset (&(h->ah.validationPayload), 0, signature_size); + return CHILD_OPS (reset_interest_for_hash, type, h); +} + +int +ah_update_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, + size_t payload_length) +{ + /* Nothing to do as there is no checksum in AH */ + return HICN_LIB_ERROR_NONE; +} + +int +ah_verify_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, + size_t payload_length) +{ + /* Nothing to do as there is no checksum in AH */ + return HICN_LIB_ERROR_NONE; +} + +int +ah_rewrite_interest (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, + ip46_address_t * addr_old) +{ + /* Nothing to do on signature */ + return HICN_LIB_ERROR_NONE; +} + +int +ah_rewrite_data (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, ip46_address_t * addr_old, + const hicn_faceid_t face_id) +{ + /* Nothing to do on signature */ + return HICN_LIB_ERROR_NONE; +} + +int +ah_get_length (hicn_type_t type, const hicn_protocol_t * h, size_t * length) +{ + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +} + +int +ah_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = AH_HDRLEN + (h->ah.payloadlen << 2); + return HICN_LIB_ERROR_NONE; +} + +int +ah_get_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + size_t child_header_length = 0; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + *header_length = AH_HDRLEN + (h->ah.payloadlen << 2) + child_header_length; + return HICN_LIB_ERROR_NONE; +} + +int +ah_get_signature_size (hicn_type_t type, const hicn_protocol_t * h, + size_t * signature_size) +{ + *signature_size = h->ah.payloadlen << 2; + return HICN_LIB_ERROR_NONE; +} + +int +ah_set_signature_size (hicn_type_t type, hicn_protocol_t * h, + const size_t signature_size) +{ + h->ah.payloadlen = signature_size >> 2; + return HICN_LIB_ERROR_NONE; +} + +int +ah_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h, + uint64_t signature_timestamp) +{ + h->ah.timestamp_as_u64 = signature_timestamp; + return HICN_LIB_ERROR_NONE; +} + +int +ah_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h, + uint64_t * signature_timestamp) +{ + *signature_timestamp = h->ah.timestamp_as_u64; + return HICN_LIB_ERROR_NONE; +} + +int +ah_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h, + uint8_t validation_algorithm) +{ + h->ah.validationAlgorithm = validation_algorithm; + return HICN_LIB_ERROR_NONE; +} + +int +ah_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h, + uint8_t * validation_algorithm) +{ + *validation_algorithm = h->ah.validationAlgorithm; + return HICN_LIB_ERROR_NONE; +} + +int +ah_set_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t *key_id) +{ + memcpy(h->ah.keyId, key_id, sizeof(h->ah.keyId)); + return HICN_LIB_ERROR_NONE; +} + +int +ah_get_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t **key_id, uint8_t *key_id_size) +{ + *key_id = h->ah.keyId; + *key_id_size = sizeof(h->ah.keyId); + return HICN_LIB_ERROR_NONE; +} + +DECLARE_HICN_OPS (ah); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/ah.h b/lib/src/protocol/ah.h new file mode 100755 index 000000000..0b4171135 --- /dev/null +++ b/lib/src/protocol/ah.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file protocol/ah.h + * @brief AH packet header + */ +#ifndef HICN_PROTOCOL_AH_H +#define HICN_PROTOCOL_AH_H + +/* + * The TCP PSH flag is set to indicate TCP payload in fact contains a AH header + * with signature information for the packet + */ +#define AH_FLAG 0x10 + +typedef struct +{ + u8 nh; // (to match with reserved in IPSEC AH) + u8 payloadlen; // Len of signature/HMAC in 4-bytes words + union + { + u16 reserved; + struct + { + u8 validationAlgorithm; // As defined in parc_SignerAlgorithm.h + u8 unused; // Unused (to match with reserved in IPSEC AH) + }; + }; + union + { + struct + { + u32 spi; + u32 seq; + }; + union + { + u8 timestamp_as_u8[8]; + u64 timestamp_as_u64; + }; // Unix timestamp indicating when the signature has been calculated + + }; + // ICV would follow + u8 keyId[32]; // Hash of the pub key + /* 44 B + validationPayload */ + u8 validationPayload[0]; // Holds the signature +} _ah_header_t; + +#define AH_HDRLEN sizeof(_ah_header_t) + +#endif /* HICN_PROTOCOL_AH_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/icmp.c b/lib/src/protocol/icmp.c new file mode 100755 index 000000000..44b646fb2 --- /dev/null +++ b/lib/src/protocol/icmp.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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 <string.h> +#include "icmp.h" + +#include "../error.h" +#include "../ops.h" + +DECLARE_get_interest_locator (icmp, UNEXPECTED) +DECLARE_set_interest_locator (icmp, UNEXPECTED) +DECLARE_get_interest_name (icmp, UNEXPECTED) +DECLARE_set_interest_name (icmp, UNEXPECTED) +DECLARE_get_interest_name_suffix (icmp, UNEXPECTED) +DECLARE_set_interest_name_suffix (icmp, UNEXPECTED) +DECLARE_get_data_locator (icmp, UNEXPECTED) +DECLARE_set_data_locator (icmp, UNEXPECTED) +DECLARE_get_data_name (icmp, UNEXPECTED) +DECLARE_set_data_name (icmp, UNEXPECTED) +DECLARE_get_data_name_suffix (icmp, UNEXPECTED) +DECLARE_set_data_name_suffix (icmp, UNEXPECTED) +DECLARE_get_data_pathlabel (icmp, UNEXPECTED) +DECLARE_set_data_pathlabel (icmp, UNEXPECTED) +DECLARE_update_data_pathlabel (icmp, UNEXPECTED) +DECLARE_get_lifetime (icmp, UNEXPECTED) +DECLARE_set_lifetime (icmp, UNEXPECTED) +DECLARE_get_length (icmp, UNEXPECTED) +DECLARE_get_payload_length (icmp, UNEXPECTED) +DECLARE_set_payload_length (icmp, UNEXPECTED) + int icmp_init_packet_header (hicn_type_t type, hicn_protocol_t * h) +{ + h->icmp = (_icmp_header_t) + { + .type = 0,.code = 0,.csum = 0,}; + + return HICN_LIB_ERROR_NONE; // CHILD_OPS(init_packet_header, type, h->icmp); +} + +int +icmp_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + h->icmp.csum = 0; + + return CHILD_OPS (reset_interest_for_hash, type, h); +} + +int +icmp_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + h->icmp.csum = 0; + + return CHILD_OPS (reset_data_for_hash, type, h); +} + +int +icmp_update_checksums (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length) +{ + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +// h->icmp.csum = 0; +// h->icmp.csum = csum(h->bytes, TCP_HDRLEN + payload_length, ~partial_csum); +// +// return CHILD_OPS(update_checksums, type, h->icmp, 0, payload_length); +} + +int +icmp_verify_checksums (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length) +{ + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +// if (csum(h->bytes, TCP_HDRLEN + payload_length, ~partial_csum) != 0) +// return HICN_LIB_ERROR_CORRUPTED_PACKET; +// return CHILD_OPS(verify_checksums, type, h->icmp, 0, payload_length); +} + +int +icmp_rewrite_interest (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, + ip46_address_t * addr_old) +{ + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +// u16 *icmp_checksum = &(h->icmp.csum); +// +// /* +// * Padding fields are set to zero so we can apply checksum on the +// * whole struct by interpreting it as IPv6 in all cases +// * +// * v4 code would be: +// * csum = ip_csum_sub_even (*icmp_checksum, h->ipv4.saddr.as_u32); +// * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32); +// */ +// u16 csum = ip_csum_sub_even (*icmp_checksum, h->ipv6.saddr.as_u64[0]); +// csum = ip_csum_sub_even (csum, h->ipv6.saddr.as_u64[1]); +// csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[0]); +// csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[1]); +// +// *icmp_checksum = ip_csum_fold (csum); +// +// return HICN_LIB_ERROR_NONE; +} + +int +icmp_rewrite_data (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, ip46_address_t * addr_old, + const hicn_faceid_t face_id) +{ + return HICN_LIB_ERROR_NOT_IMPLEMENTED; +// u16 *icmp_checksum = &(h->icmp.csum); +// +// /* +// * Padding fields are set to zero so we can apply checksum on the +// * whole struct by interpreting it as IPv6 in all cases +// * +// * v4 code would be: +// * csum = ip_csum_sub_even (*icmp_checksum, h->ipv4.saddr.as_u32); +// * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32); +// */ +// u16 csum = ip_csum_sub_even (*icmp_checksum, addr_old->ip6.as_u64[0]); +// csum = ip_csum_sub_even (*icmp_checksum, addr_old->ip6.as_u64[1]); +// csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[0]); +// csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[1]); +// +// csum = ip_csum_sub_even (csum, h->icmp.pathlabel); +// icmp_update_data_pathlabel(type, h, face_id); +// csum = ip_csum_add_even (csum, h->icmp.pathlabel); +// +// *icmp_checksum = ip_csum_fold (csum); +// +// return HICN_LIB_ERROR_NONE; +} + +int +icmp_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = ICMP_HDRLEN; + return HICN_LIB_ERROR_NONE; +} + +int +icmp_get_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + size_t child_header_length = 0; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + + *header_length = ICMP_HDRLEN + child_header_length; + return HICN_LIB_ERROR_NONE; +} + +int +icmp_get_signature_size (hicn_type_t type, const hicn_protocol_t * h, + size_t * signature_size) +{ + return CHILD_OPS (get_signature_size, type, h, signature_size); +} + +int +icmp_set_signature_size (hicn_type_t type, hicn_protocol_t * h, + size_t signature_size) +{ + return CHILD_OPS (set_signature_size, type, h, signature_size); +} + +int +icmp_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h, + uint64_t signature_timestamp) +{ + return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp); +} + +int +icmp_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h, + uint64_t * signature_timestamp) +{ + return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp); +} + +int +icmp_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h, + uint8_t validation_algorithm) +{ + return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm); +} + +int +icmp_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h, + uint8_t * validation_algorithm) +{ + return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm); +} + +int +icmp_set_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t *key_id) +{ + return CHILD_OPS (set_key_id, type, h, key_id); +} + +int +icmp_get_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t **key_id, uint8_t *key_id_size) +{ + return CHILD_OPS (get_key_id, type, h, key_id, key_id_size); +} + +DECLARE_HICN_OPS (icmp); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/icmp.h b/lib/src/protocol/icmp.h new file mode 100755 index 000000000..5a84995b6 --- /dev/null +++ b/lib/src/protocol/icmp.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file protocol/icmp.h + * @brief ICMP packet header + */ +#ifndef HICN_PROTOCOL_ICMP_H +#define HICN_PROTOCOL_ICMP_H + +#include "../common.h" + +typedef struct +{ + u8 type; + u8 code; + u16 csum; +} _icmp_header_t; + +typedef struct +{ + u8 type; + u8 code; + u16 csum; + union + { + struct + { + u16 id; + u16 sequence; + } echo; /* echo datagram */ + u32 gateway; /* gateway address */ + struct + { + u16 _unused; + u16 mtu; + } frag; /* path mtu discovery */ + struct + { + u16 expected_lbl; + u16 received_lbl; + } wldr_notification_lbl; + }; +} _icmp_wldr_header_t; + +#define ICMP_HDRLEN sizeof(_icmp_header_t) + +#endif /* HICN_PROTOCOL_ICMP_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/icmprd.h b/lib/src/protocol/icmprd.h new file mode 100755 index 000000000..c2f27d673 --- /dev/null +++ b/lib/src/protocol/icmprd.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file protocol/icmp-rd.c + * @brief hICN operations for ICMP Redirect header + */ +#ifndef HICN_PROTOCOL_ICMPRD_H +#define HICN_PROTOCOL_ICMPRD_H + +#include "../common.h" + +typedef struct __attribute__ ((__packed__)) +{ + ip4_address_t ip; + _ipv4_header_t iph; + u8 data[64]; +} _icmprd4_header_t; + +typedef struct __attribute__ ((__packed__)) +{ + u32 res; + ip6_address_t tgt; + ip6_address_t dst; +} _icmprd_header_t; + +#endif /* HICN_PROTOCOL_ICMPRD_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/ipv4.c b/lib/src/protocol/ipv4.c new file mode 100755 index 000000000..7c6af127d --- /dev/null +++ b/lib/src/protocol/ipv4.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +/** + * @file protocol/ipv4.c + * @brief hICN operations for IPv4 header + * + * NOTE: IPv4 options (affecting the header size) are currently not supported. + */ + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> + +#include "../error.h" +#include "../ops.h" +#include "../common.h" +#include "../header.h" + +#include "ipv4.h" + +int ipv4_get_payload_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * payload_length); + +int +ipv4_init_packet_header (hicn_type_t type, hicn_protocol_t * h) +{ + size_t total_header_length; + int rc = + hicn_ops_vft[type.l1]->get_header_length (type, h, &total_header_length); + if (rc < 0) + return rc; + + h->ipv4 = (_ipv4_header_t) + { + .version_ihl = + (IPV4_DEFAULT_VERSION << 4) | (0x0f & IPV4_DEFAULT_IHL),.tos = + IPV4_DEFAULT_TOS,.len = htons ((u16) total_header_length),.id = + htons (IPV4_DEFAULT_ID),.frag_off = + htons (IPV4_DEFAULT_FRAG_OFF),.ttl = HICN_DEFAULT_TTL,.protocol = + type.l2,.csum = 0,.saddr.as_u32 = 0,.daddr.as_u32 = 0,}; + + return CHILD_OPS (init_packet_header, type, h); +} + +int +ipv4_get_interest_locator (hicn_type_t type, const hicn_protocol_t * h, + ip46_address_t * ip_address) +{ + ip_address->ip4 = h->ipv4.saddr; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_set_interest_locator (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * ip_address) +{ + h->ipv4.saddr = ip_address->ip4; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_get_interest_name (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_t * name) +{ + name->ip4.prefix_as_ip4 = h->ipv4.daddr; +#ifndef HICN_VPP_PLUGIN + name->type = HNT_CONTIGUOUS_V4; + name->len = HICN_V4_NAME_LEN; +#endif /* HICN_VPP_PLUGIN */ + return CHILD_OPS (get_interest_name_suffix, type, h, &(name->ip4.suffix)); +} + +int +ipv4_set_interest_name (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_t * name) +{ + h->ipv4.daddr = name->ip4.prefix_as_ip4; + return CHILD_OPS (set_interest_name_suffix, type, h, &(name->ip4.suffix)); +} + +int +ipv4_get_interest_name_suffix (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (set_interest_name_suffix, type, h, suffix); +} + +int +ipv4_set_interest_name_suffix (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (set_interest_name_suffix, type, h, suffix); +} + +int +ipv4_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + /* Sets everything to 0 up to IP destination address */ + memset (&(h->ipv4), 0, 16); + + return CHILD_OPS (reset_interest_for_hash, type, h); +} + +int +ipv4_get_data_locator (hicn_type_t type, const hicn_protocol_t * h, + ip46_address_t * ip_address) +{ + ip_address->ip4 = h->ipv4.daddr; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_set_data_locator (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * ip_address) +{ + h->ipv4.daddr = ip_address->ip4; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_get_data_name (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_t * name) +{ + name->ip4.prefix_as_ip4 = h->ipv4.saddr; +#ifndef HICN_VPP_PLUGIN + name->type = HNT_CONTIGUOUS_V4; + name->len = HICN_V4_NAME_LEN; +#endif /* HICN_VPP_PLUGIN */ + return CHILD_OPS (get_data_name_suffix, type, h, &(name->ip4.suffix)); +} + +int +ipv4_set_data_name (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_t * name) +{ + h->ipv4.saddr = name->ip4.prefix_as_ip4; + return CHILD_OPS (set_data_name_suffix, type, h, &(name->ip4.suffix)); +} + +int +ipv4_get_data_name_suffix (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (get_data_name_suffix, type, h, suffix); +} + +int +ipv4_set_data_name_suffix (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (set_data_name_suffix, type, h, suffix); +} + +int +ipv4_get_data_pathlabel (hicn_type_t type, const hicn_protocol_t * h, + u32 * pathlabel) +{ + return CHILD_OPS (get_data_pathlabel, type, h, pathlabel); +} + +int +ipv4_set_data_pathlabel (hicn_type_t type, hicn_protocol_t * h, + const u32 pathlabel) +{ + return CHILD_OPS (set_data_pathlabel, type, h, pathlabel); +} + +int +ipv4_update_data_pathlabel (hicn_type_t type, hicn_protocol_t * h, + const hicn_faceid_t face_id) +{ + return CHILD_OPS (update_data_pathlabel, type, h, face_id); +} + +int +ipv4_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + /* Sets everything to 0 up to source address */ + memset (&h->ipv4, 0, 12); + /* Clears destination address */ + memset (&(h->ipv4.daddr), 0, 4); + + return CHILD_OPS (reset_data_for_hash, type, h); +} + +int +ipv4_get_lifetime (hicn_type_t type, const hicn_protocol_t * h, + hicn_lifetime_t * lifetime) +{ + return CHILD_OPS (get_lifetime, type, h, lifetime); +} + +int +ipv4_set_lifetime (hicn_type_t type, hicn_protocol_t * h, + const hicn_lifetime_t lifetime) +{ + return CHILD_OPS (set_lifetime, type, h, lifetime); +} + +int +ipv4_update_checksums (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length) +{ + /* + * Checksum field is not accounted for in lower layers, so we can compute + * them in any order. Note that it is only a header checksum. + */ + h->ipv4.csum = 0; + h->ipv4.csum = csum (h, IPV4_HDRLEN, 0); + + /* Retrieve payload length if not specified, as it is not available later */ + if (payload_length == 0) + { + int rc = ipv4_get_payload_length (type, h, &payload_length); + if (rc < 0) + return rc; + } + + /* Ignore the payload if payload_length = ~0 */ + if (payload_length == ~0) + { + payload_length = 0; + } + + /* Build pseudo-header */ + ipv4_pseudo_header_t psh; + psh.ip_src = h->ipv4.saddr; + psh.ip_dst = h->ipv4.daddr; + /* Size is u32 and not u16, we cannot copy and need to care about endianness */ + psh.size = htons (ntohs (h->ipv4.len) - (u16) IPV4_HDRLEN); + psh.zero = 0; + psh.protocol = (u8) h->ipv4.protocol; + + /* Compute partial checksum based on pseudo-header */ + if (partial_csum != 0) + { + partial_csum = ~partial_csum; + } + partial_csum = csum (&psh, IPV4_PSHDRLEN, partial_csum); + + return CHILD_OPS (update_checksums, type, h, partial_csum, payload_length); +} + +int +ipv4_verify_checksums (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length) +{ + /* + * Checksum field is not accounted for in lower layers, so we can compute + * them in any order. Note that it is only a header checksum. + */ + if (csum (h, IPV4_HDRLEN, 0) != 0) + return HICN_LIB_ERROR_CORRUPTED_PACKET; + + /* Retrieve payload length if not specified, as it is not available later */ + if (payload_length == 0) + { + int rc = ipv4_get_payload_length (type, h, &payload_length); + if (rc < 0) + return rc; + } + + /* Build pseudo-header */ + ipv4_pseudo_header_t psh; + psh.ip_src = h->ipv4.saddr; + psh.ip_dst = h->ipv4.daddr; + /* Size is u32 and not u16, we cannot copy and need to care about endianness */ + psh.size = htons (ntohs (h->ipv4.len) - (u16) IPV4_HDRLEN); + psh.zero = 0; + psh.protocol = (u8) h->ipv4.protocol; + + /* Compute partial checksum based on pseudo-header */ + partial_csum = csum (&psh, IPV4_PSHDRLEN, 0); + + return CHILD_OPS (update_checksums, type, h, partial_csum, payload_length); +} + +int +ipv4_rewrite_interest (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, + ip46_address_t * addr_old) +{ + // ASSERT(addr_old == NULL); + addr_old->ip4 = h->ipv4.saddr; + addr_old->pad[0] = 0; + addr_old->pad[1] = 0; + addr_old->pad[2] = 0; + + h->ipv4.saddr = addr_new->ip4; + h->ipv4.csum = 0; + h->ipv4.csum = csum (&h->ipv4, IPV4_HDRLEN, 0); + + return CHILD_OPS (rewrite_interest, type, h, addr_new, addr_old); +} + +int +ipv4_rewrite_data (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, ip46_address_t * addr_old, + const hicn_faceid_t face_id) +{ + // ASSERT(addr_old == NULL); + addr_old->ip4 = h->ipv4.daddr; + addr_old->pad[0] = 0; + addr_old->pad[1] = 0; + addr_old->pad[2] = 0; + + h->ipv4.daddr = addr_new->ip4; + h->ipv4.csum = 0; + h->ipv4.csum = csum (&h->ipv4, IPV4_HDRLEN, 0); + + return CHILD_OPS (rewrite_data, type, h, addr_new, addr_old, face_id); +} + +int +ipv4_get_current_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = IPV4_HDRLEN; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_get_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = h->ipv4.len; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = IPV4_HDRLEN; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_get_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + size_t child_header_length = 0; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + *header_length = IPV4_HDRLEN + child_header_length; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_get_payload_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * payload_length) +{ + size_t child_header_length; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + *payload_length = htons (h->ipv4.len) - IPV4_HDRLEN - child_header_length; + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_set_payload_length (hicn_type_t type, hicn_protocol_t * h, + size_t payload_length) +{ + size_t child_header_length; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + h->ipv4.len = htons (payload_length + IPV4_HDRLEN + child_header_length); + return HICN_LIB_ERROR_NONE; +} + +int +ipv4_get_signature_size (hicn_type_t type, const hicn_protocol_t * h, + size_t * signature_size) +{ + return CHILD_OPS (get_signature_size, type, h, signature_size); +} + +int +ipv4_set_signature_size (hicn_type_t type, hicn_protocol_t * h, + size_t signature_size) +{ + return CHILD_OPS (set_signature_size, type, h, signature_size); +} + +int +ipv4_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h, + uint64_t signature_timestamp) +{ + return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp); +} + +int +ipv4_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h, + uint64_t * signature_timestamp) +{ + return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp); +} + +int +ipv4_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h, + uint8_t validation_algorithm) +{ + return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm); +} + +int +ipv4_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h, + uint8_t * validation_algorithm) +{ + return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm); +} + +int +ipv4_set_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t *key_id) +{ + return CHILD_OPS (set_key_id, type, h, key_id); +} + +int +ipv4_get_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t **key_id, uint8_t *key_id_size) +{ + return CHILD_OPS (get_key_id, type, h, key_id, key_id_size); +} + +DECLARE_HICN_OPS (ipv4); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/ipv4.h b/lib/src/protocol/ipv4.h new file mode 100755 index 000000000..c57485b6c --- /dev/null +++ b/lib/src/protocol/ipv4.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +#ifndef HICN_PROTOCOL_IPV4 +#define HICN_PROTOCOL_IPV4 + +#include "../base.h" +#include "../common.h" +#include "../protocol.h" + +/* Headers were adapted from linux' definitions in netinet/ip.h */ + +typedef struct +{ + union + { + struct + { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + u8 ihl:4; + u8 version:4; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u8 version:4; + u8 ihl:4; +#else +#error "Unsupported endianness" +#endif + }; + + u8 version_ihl; + }; + u8 tos; + u16 len; + u16 id; + u16 frag_off; + u8 ttl; + u8 protocol; + u16 csum; + ip4_address_t saddr; + ip4_address_t daddr; +} _ipv4_header_t; + +#define ipv4_header_bytes(ipv4_header) (sizeof(u32) * (ipv4_header->version_ihl & 0xf)) + +#define IPV4_HDRLEN sizeof(_ipv4_header_t) + +typedef struct +{ + ip4_address_t ip_src; + ip4_address_t ip_dst; + u8 zero; + u8 protocol; + u16 size; +} ipv4_pseudo_header_t; + +#define IPV4_PSHDRLEN sizeof(ipv4_pseudo_header_t) + +/* Default field values */ +#define IPV4_DEFAULT_VERSION 4 +#define IPV4_DEFAULT_IHL 5 +#define IPV4_DEFAULT_TOS 0 +#define IPV4_DEFAULT_PAYLOAD_LENGTH 0 +#define IPV4_DEFAULT_ID 300 +#define IPV4_DEFAULT_FRAG_OFF 0x000 +#define IPV4_DEFAULT_TTL 64 +#define IPV4_DEFAULT_PROTOCOL IPPROTO_TCP +#define IPV4_DEFAULT_SRC_IP 0, 0, 0, 0 +#define IPV4_DEFAULT_DST_IP 0, 0, 0, 0 + + +#endif /* HICN_PROTOCOL_IPV4 */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/ipv6.c b/lib/src/protocol/ipv6.c new file mode 100755 index 000000000..41b00ec92 --- /dev/null +++ b/lib/src/protocol/ipv6.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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 <stdlib.h> +#include <string.h> + +#include "../common.h" +#include "../error.h" +#include "../ops.h" + +int +ipv6_get_payload_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * payload_length); + +int +ipv6_init_packet_header (hicn_type_t type, hicn_protocol_t * h) +{ + size_t total_header_length; + int rc = CHILD_OPS (get_header_length, type, h, &total_header_length); + if (rc < 0) + return rc; + + /* *INDENT-OFF* */ + h->ipv6 = (_ipv6_header_t) + { + .saddr = {{ 0 }} + ,.daddr = {{ 0 }} + ,.version_class_flow = htonl ((IPV6_DEFAULT_VERSION << 28) | + (IPV6_DEFAULT_TRAFFIC_CLASS << 20) | + (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)), + .len = htons ((u16) total_header_length), + .nxt = type.l2, + .hlim = HICN_DEFAULT_TTL, + }; + /* *INDENT-ON* */ + return CHILD_OPS (init_packet_header, type, h); +} + +int +ipv6_get_interest_locator (hicn_type_t type, const hicn_protocol_t * h, + ip46_address_t * ip_address) +{ + ip_address->ip6 = h->ipv6.saddr; + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_set_interest_locator (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * ip_address) +{ + h->ipv6.saddr = ip_address->ip6; + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_get_interest_name (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_t * name) +{ + name->ip6.prefix_as_ip6 = h->ipv6.daddr; +#ifndef HICN_VPP_PLUGIN + name->type = HNT_CONTIGUOUS_V6; + name->len = HICN_V6_NAME_LEN; +#endif /* HICN_VPP_PLUGIN */ + return CHILD_OPS (get_interest_name_suffix, type, h, &(name->ip6.suffix)); +} + +int +ipv6_set_interest_name (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_t * name) +{ + h->ipv6.daddr = name->ip6.prefix_as_ip6; + return CHILD_OPS (set_interest_name_suffix, type, h, &(name->ip6.suffix)); +} + +int +ipv6_get_interest_name_suffix (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (get_interest_name_suffix, type, h, suffix); +} + +int +ipv6_set_interest_name_suffix (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (set_interest_name_suffix, type, h, suffix); +} + +int +ipv6_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + /* Sets everything to 0 up to IP destination address */ + memset (&(h->ipv6), 0, 24); + + return CHILD_OPS (reset_interest_for_hash, type, h); +} + +int +ipv6_get_data_locator (hicn_type_t type, const hicn_protocol_t * h, + ip46_address_t * ip_address) +{ + ip_address->ip6 = h->ipv6.daddr; + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_set_data_locator (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * ip_address) +{ + h->ipv6.daddr = ip_address->ip6; + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_get_data_name (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_t * name) +{ + name->ip6.prefix_as_ip6 = h->ipv6.saddr; +#ifndef HICN_VPP_PLUGIN + name->type = HNT_CONTIGUOUS_V6; + name->len = HICN_V6_NAME_LEN; +#endif /* HICN_VPP_PLUGIN */ + return CHILD_OPS (get_data_name_suffix, type, h, &(name->ip6.suffix)); +} + +int +ipv6_set_data_name (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_t * name) +{ + h->ipv6.saddr = name->ip6.prefix_as_ip6; + return CHILD_OPS (set_data_name_suffix, type, h, &(name->ip6.suffix)); +} + +int +ipv6_get_data_name_suffix (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (get_data_name_suffix, type, h, suffix); +} + +int +ipv6_set_data_name_suffix (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix) +{ + return CHILD_OPS (set_data_name_suffix, type, h, suffix); +} + +int +ipv6_get_data_pathlabel (hicn_type_t type, const hicn_protocol_t * h, + u32 * pathlabel) +{ + return CHILD_OPS (get_data_pathlabel, type, h, pathlabel); +} + +int +ipv6_set_data_pathlabel (hicn_type_t type, hicn_protocol_t * h, + const u32 pathlabel) +{ + return CHILD_OPS (set_data_pathlabel, type, h, pathlabel); +} + +int +ipv6_update_data_pathlabel (hicn_type_t type, hicn_protocol_t * h, + const hicn_faceid_t face_id) +{ + return CHILD_OPS (update_data_pathlabel, type, h, face_id); +} + +int +ipv6_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + /* IP: Set everithing to 0 up to destination address */ + memset (&h->ipv6, 0, 8); + /* Clears destination address */ + memset (&(h->ipv6.daddr), 0, 16); + + return CHILD_OPS (reset_data_for_hash, type, h); +} + +int +ipv6_get_lifetime (hicn_type_t type, const hicn_protocol_t * h, + hicn_lifetime_t * lifetime) +{ + return CHILD_OPS (get_lifetime, type, h, lifetime); +} + +int +ipv6_set_lifetime (hicn_type_t type, hicn_protocol_t * h, + const hicn_lifetime_t lifetime) +{ + return CHILD_OPS (set_lifetime, type, h, lifetime); +} + +int +ipv6_update_checksums (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length) +{ + /* Retrieve payload length if not specified */ + if (payload_length == 0) + { + int rc = ipv6_get_payload_length (type, h, &payload_length); + if (rc < 0) + return rc; + } + + /* Ignore the payload if payload_length = ~0 */ + if (payload_length == ~0) + { + payload_length = 0; + } + + /* Build pseudo-header */ + ipv6_pseudo_header_t psh; + psh.ip_src = h->ipv6.saddr; + psh.ip_dst = h->ipv6.daddr; + /* Size is u32 and not u16, we cannot copy and need to care about endianness */ + psh.size = htonl (ntohs (h->ipv6.len)); + psh.zeros = 0; + psh.zero = 0; + psh.protocol = h->ipv6.nxt; + + /* Compute partial checksum based on pseudo-header */ + if (partial_csum != 0) + { + partial_csum = ~partial_csum; + } + partial_csum = csum (&psh, IPV6_PSHDRLEN, partial_csum); + + return CHILD_OPS (update_checksums, type, h, partial_csum, payload_length); +} + +int +ipv6_verify_checksums (hicn_type_t type, hicn_protocol_t * h, + u16 partial_csum, size_t payload_length) +{ + /* Retrieve payload length if not specified */ + if (payload_length == 0) + { + int rc = ipv6_get_payload_length (type, h, &payload_length); + if (rc < 0) + return rc; + } + + /* Build pseudo-header */ + ipv6_pseudo_header_t pseudo; + pseudo.ip_src = h->ipv6.saddr; + pseudo.ip_dst = h->ipv6.daddr; + /* Size is u32 and not u16, we cannot copy and need to care about endianness */ + pseudo.size = htonl (ntohs (h->ipv6.len)); + pseudo.zeros = 0; + pseudo.zero = 0; + pseudo.protocol = h->ipv6.nxt; + + /* Compute partial checksum based on pseudo-header */ + partial_csum = csum (&pseudo, IPV6_PSHDRLEN, 0); + + return CHILD_OPS (verify_checksums, type, h, partial_csum, payload_length); +} + +int +ipv6_rewrite_interest (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, + ip46_address_t * addr_old) +{ + // ASSERT(addr_old == NULL); + addr_old->ip6 = h->ipv6.saddr; + h->ipv6.saddr = addr_new->ip6; + + return CHILD_OPS (rewrite_interest, type, h, addr_new, addr_old); +} + +int +ipv6_rewrite_data (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, ip46_address_t * addr_old, + const hicn_faceid_t face_id) +{ + // ASSERT(addr_old == NULL); + addr_old->ip6 = h->ipv6.daddr; + h->ipv6.daddr = addr_new->ip6; + + return CHILD_OPS (rewrite_data, type, h, addr_new, addr_old, face_id); +} + +int +ipv6_get_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = IPV6_HDRLEN + ntohs (h->ipv6.len); + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = IPV6_HDRLEN; + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_get_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + size_t child_header_length = 0; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + *header_length = IPV6_HDRLEN + child_header_length; + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_get_payload_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * payload_length) +{ + size_t child_header_length; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + *payload_length = ntohs (h->ipv6.len) - child_header_length; + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_set_payload_length (hicn_type_t type, hicn_protocol_t * h, + size_t payload_length) +{ + size_t child_header_length; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + h->ipv6.len = htons (payload_length + child_header_length); + return HICN_LIB_ERROR_NONE; +} + +int +ipv6_get_signature_size (hicn_type_t type, const hicn_protocol_t * h, + size_t * signature_size) +{ + return CHILD_OPS (get_signature_size, type, h, signature_size); +} + +int +ipv6_set_signature_size (hicn_type_t type, hicn_protocol_t * h, + size_t signature_size) +{ + return CHILD_OPS (set_signature_size, type, h, signature_size); +} + +int +ipv6_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h, + uint64_t signature_timestamp) +{ + return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp); +} + +int +ipv6_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h, + uint64_t * signature_timestamp) +{ + return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp); +} + +int +ipv6_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h, + uint8_t validation_algorithm) +{ + return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm); +} + +int +ipv6_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h, + uint8_t * validation_algorithm) +{ + return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm); +} + +int +ipv6_set_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t *key_id) +{ + return CHILD_OPS (set_key_id, type, h, key_id); +} + +int +ipv6_get_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t **key_id, uint8_t *key_id_size) +{ + return CHILD_OPS (get_key_id, type, h, key_id, key_id_size); +} + +DECLARE_HICN_OPS (ipv6); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/ipv6.h b/lib/src/protocol/ipv6.h new file mode 100755 index 000000000..28a1aa47f --- /dev/null +++ b/lib/src/protocol/ipv6.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +#ifndef HICN_PROTOCOL_IPV6_H +#define HICN_PROTOCOL_IPV6_H + +#include "../common.h" + +typedef struct +{ + union + { + struct + { + u32 version_class_flow; /* version, traffic class and 20 bits of flow-ID */ + u16 len; /* payload length */ + u8 nxt; /* next header */ + u8 hlim; /* hop limit */ + }; + u8 vfc; /* 4 bits version, top 4 bits class */ + }; + ip6_address_t saddr; /* source address */ + ip6_address_t daddr; /* destination address */ +} _ipv6_header_t; + + +#define IPV6_HDRLEN sizeof(_ipv6_header_t) + +typedef struct +{ + ip6_address_t ip_src; + ip6_address_t ip_dst; + u32 size; + u16 zeros; + u8 zero; + u8 protocol; +} ipv6_pseudo_header_t; + +#define IPV6_PSHDRLEN sizeof(ipv6_pseudo_header_t) + +/* Default field values */ +#define IPV6_DEFAULT_VERSION 6 +#define IPV6_DEFAULT_TRAFFIC_CLASS 0 +#define IPV6_DEFAULT_FLOW_LABEL 0 +#define IPV6_DEFAULT_PAYLOAD_LENGTH 0 + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/tcp.c b/lib/src/protocol/tcp.c new file mode 100755 index 000000000..2afc4f6f4 --- /dev/null +++ b/lib/src/protocol/tcp.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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 <string.h> +#include "tcp.h" + +#include "../error.h" +#include "../ops.h" + +#define TCP_DEFAULT_SRC_PORT 0x8000 +#define TCP_DEFAULT_DST_PORT 0x0080 +#define TCP_DEFAULT_WINDOW_SIZE 0 // In [2, 65535] +#define TCP_DEFAULT_HLEN 20 +#define TCP_DEFAULT_DATA_OFFSET_RES (TCP_DEFAULT_HLEN >> 2) << 4 +#define TCP_DEFAULT_CWR 0 +#define TCP_DEFAULT_ECE 0 +#define TCP_DEFAULT_URG 0 +#define TCP_DEFAULT_ACK 0 +#define TCP_DEFAULT_PSH 0 +#define TCP_DEFAULT_RST 0 +#define TCP_DEFAULT_SYN 1 +#define TCP_DEFAULT_FIN 0 + +DECLARE_get_interest_locator (tcp, UNEXPECTED); +DECLARE_set_interest_locator (tcp, UNEXPECTED); +DECLARE_get_interest_name (tcp, UNEXPECTED); +DECLARE_set_interest_name (tcp, UNEXPECTED); +DECLARE_get_data_locator (tcp, UNEXPECTED); +DECLARE_set_data_locator (tcp, UNEXPECTED); +DECLARE_get_data_name (tcp, UNEXPECTED); +DECLARE_set_data_name (tcp, UNEXPECTED); +DECLARE_get_length (tcp, UNEXPECTED); +DECLARE_get_payload_length (tcp, UNEXPECTED); +DECLARE_set_payload_length (tcp, UNEXPECTED); + +int +tcp_init_packet_header (hicn_type_t type, hicn_protocol_t * h) +{ + h->tcp = (_tcp_header_t) + { + .sport = htons (TCP_DEFAULT_SRC_PORT),.dport = + htons (TCP_DEFAULT_DST_PORT),.seq = 0,.seq_ack = + 0,.data_offset_and_reserved = TCP_DEFAULT_DATA_OFFSET_RES,.flags = + TCP_DEFAULT_CWR << 7 | TCP_DEFAULT_ECE << 6 | TCP_DEFAULT_URG << 5 | + TCP_DEFAULT_ACK << 4 | TCP_DEFAULT_PSH << 3 | TCP_DEFAULT_RST << 2 | + TCP_DEFAULT_SYN << 1 | TCP_DEFAULT_FIN << 0,.window = + htons (TCP_DEFAULT_WINDOW_SIZE),.csum = 0,.urg_ptr = 65000,}; + + return CHILD_OPS (init_packet_header, type, h); +} + +int +tcp_get_interest_name_suffix (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_suffix_t * suffix) +{ + *suffix = ntohl (h->tcp.name_suffix); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_interest_name_suffix (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix) +{ + h->tcp.name_suffix = htonl (*suffix); + + return HICN_LIB_ERROR_NONE; +} + +int +tcp_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + memset (&(h->tcp), 0, 4); + memset (&(h->tcp.seq_ack), 0, 12); + + return CHILD_OPS (reset_interest_for_hash, type, h); +} + + +int +tcp_get_data_name_suffix (hicn_type_t type, const hicn_protocol_t * h, + hicn_name_suffix_t * suffix) +{ + *suffix = ntohl (h->tcp.name_suffix); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_data_name_suffix (hicn_type_t type, hicn_protocol_t * h, + const hicn_name_suffix_t * suffix) +{ + h->tcp.name_suffix = htonl (*suffix); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_get_data_pathlabel (hicn_type_t type, const hicn_protocol_t * h, + u32 * pathlabel) +{ + *pathlabel = h->tcp.seq_ack; + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_data_pathlabel (hicn_type_t type, hicn_protocol_t * h, + const u32 pathlabel) +{ + h->tcp.seq_ack = pathlabel; + return HICN_LIB_ERROR_NONE; +} + +int +tcp_update_data_pathlabel (hicn_type_t type, hicn_protocol_t * h, + const hicn_faceid_t face_id) +{ + hicn_pathlabel_t pl = + (hicn_pathlabel_t) ((h->tcp.pathlabel & HICN_PATH_LABEL_MASK) >> (32 - + HICN_PATH_LABEL_SIZE)); + hicn_pathlabel_t new_pl; + + update_pathlabel (pl, face_id, &new_pl); + h->tcp.pathlabel = new_pl; + + return HICN_LIB_ERROR_NONE; +} + +int +tcp_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h) +{ + memset (&(h->tcp), 0, 4); + memset (&(h->tcp.seq_ack), 0, 12); + + return CHILD_OPS (reset_data_for_hash, type, h); +} + + +int +tcp_get_lifetime (hicn_type_t type, const hicn_protocol_t * h, + hicn_lifetime_t * lifetime) +{ + *lifetime = + ntohs (h->tcp.urg_ptr) << (h->tcp.data_offset_and_reserved & 0xF); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_lifetime (hicn_type_t type, hicn_protocol_t * h, + const hicn_lifetime_t lifetime) +{ + u8 multiplier = 0; + u32 lifetime_scaled = lifetime; + + if (PREDICT_FALSE (lifetime >= HICN_MAX_LIFETIME)) + { + h->tcp.urg_ptr = htons (HICN_MAX_LIFETIME_SCALED); + h->tcp.data_offset_and_reserved = + (h-> + tcp.data_offset_and_reserved & ~0xF) | HICN_MAX_LIFETIME_MULTIPLIER; + return HICN_LIB_ERROR_NONE; + } + + while (lifetime_scaled > HICN_MAX_LIFETIME_SCALED + && multiplier <= HICN_MAX_LIFETIME_MULTIPLIER) + { + multiplier++; + lifetime_scaled = lifetime_scaled >> 1; + } + + h->tcp.urg_ptr = htons (lifetime_scaled); + h->tcp.data_offset_and_reserved = + (h->tcp.data_offset_and_reserved & ~0xF) | multiplier; + + return HICN_LIB_ERROR_NONE; +} + +int +tcp_update_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, + size_t payload_length) +{ + h->tcp.csum = 0; + + if (PREDICT_TRUE (partial_csum != 0)) + { + partial_csum = ~partial_csum; + } + + h->tcp.csum = csum (h, TCP_HDRLEN + payload_length, partial_csum); + + return CHILD_OPS (update_checksums, type, h, 0, payload_length); +} + +int +tcp_verify_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, + size_t payload_length) +{ + if (csum (h, TCP_HDRLEN + payload_length, ~partial_csum) != 0) + return HICN_LIB_ERROR_CORRUPTED_PACKET; + return CHILD_OPS (verify_checksums, type, h, 0, payload_length); +} + +#define TCP_OFFSET_MASK 13 +#define TCP_OFFSET_DATA_OFFSET 12 +#define TCP_OFFSET_IN_BITS_DATA_OFFSET 0 +#define TCP_OFFSET_IN_BITS_RESERVED 4 +#define TCP_OFFSET_IN_BITS_NS 7 + +#define TCP_DEFAULT_SRC_PORT 0x8000 +#define TCP_DEFAULT_DST_PORT 0x0080 +#define TCP_DEFAULT_WINDOW_SIZE 0 // In [2, 65535] +#define TCP_DEFAULT_DATA_OFFSET 5 // Size of the TCP header in words (= 4 bytes). Must be greater or equal than 5. +#define TCP_DEFAULT_CWR 0 +#define TCP_DEFAULT_ECE 0 +#define TCP_DEFAULT_URG 0 +#define TCP_DEFAULT_ACK 0 +#define TCP_DEFAULT_PSH 0 +#define TCP_DEFAULT_RST 0 +#define TCP_DEFAULT_SYN 1 +#define TCP_DEFAULT_FIN 0 + +int +tcp_rewrite_interest (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, + ip46_address_t * addr_old) +{ + u16 *tcp_checksum = &(h->tcp.csum); + + /* + * Padding fields are set to zero so we can apply checksum on the + * whole struct by interpreting it as IPv6 in all cases + * + * v4 code would be: + * csum = ip_csum_sub_even (*tcp_checksum, h->ipv4.saddr.as_u32); + * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32); + */ + u16 csum = ip_csum_sub_even (*tcp_checksum, h->ipv6.saddr.as_u64[0]); + csum = ip_csum_sub_even (csum, h->ipv6.saddr.as_u64[1]); + csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[0]); + csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[1]); + + *tcp_checksum = ip_csum_fold (csum); + + return HICN_LIB_ERROR_NONE; +} + +int +tcp_rewrite_data (hicn_type_t type, hicn_protocol_t * h, + const ip46_address_t * addr_new, ip46_address_t * addr_old, + const hicn_faceid_t face_id) +{ + u16 *tcp_checksum = &(h->tcp.csum); + + /* + * Padding fields are set to zero so we can apply checksum on the + * whole struct by interpreting it as IPv6 in all cases + * + * v4 code would be: + * csum = ip_csum_sub_even (*tcp_checksum, h->ipv4.saddr.as_u32); + * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32); + */ + u16 csum = ip_csum_sub_even (*tcp_checksum, addr_old->ip6.as_u64[0]); + csum = ip_csum_sub_even (*tcp_checksum, addr_old->ip6.as_u64[1]); + csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[0]); + csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[1]); + + csum = ip_csum_sub_even (csum, h->tcp.pathlabel); + tcp_update_data_pathlabel (type, h, face_id); + csum = ip_csum_add_even (csum, h->tcp.pathlabel); + + *tcp_checksum = ip_csum_fold (csum); + + return HICN_LIB_ERROR_NONE; +} + +int +tcp_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + *header_length = TCP_HDRLEN; + return HICN_LIB_ERROR_NONE; +} + +int +tcp_get_header_length (hicn_type_t type, const hicn_protocol_t * h, + size_t * header_length) +{ + size_t child_header_length = 0; + int rc = CHILD_OPS (get_header_length, type, h, &child_header_length); + if (rc < 0) + return rc; + + *header_length = TCP_HDRLEN + child_header_length; + return HICN_LIB_ERROR_NONE; +} + +int +tcp_get_signature_size (hicn_type_t type, const hicn_protocol_t * h, + size_t * signature_size) +{ + return CHILD_OPS (get_signature_size, type, h, signature_size); +} + +int +tcp_set_signature_size (hicn_type_t type, hicn_protocol_t * h, + size_t signature_size) +{ + return CHILD_OPS (set_signature_size, type, h, signature_size); +} + +int +tcp_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h, + uint64_t signature_timestamp) +{ + return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp); +} + +int +tcp_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h, + uint64_t * signature_timestamp) +{ + return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp); +} + +int +tcp_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h, + uint8_t validation_algorithm) +{ + return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm); +} + +int +tcp_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h, + uint8_t * validation_algorithm) +{ + return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm); +} + +int +tcp_set_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t *key_id) +{ + return CHILD_OPS (set_key_id, type, h, key_id); +} + +int +tcp_get_key_id (hicn_type_t type, hicn_protocol_t * h, + uint8_t **key_id, uint8_t *key_id_size) +{ + return CHILD_OPS (get_key_id, type, h, key_id, key_id_size); +} + +DECLARE_HICN_OPS (tcp); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/tcp.h b/lib/src/protocol/tcp.h new file mode 100755 index 000000000..68f4bf8f9 --- /dev/null +++ b/lib/src/protocol/tcp.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +#ifndef HICN_PROTOCOL_TCP_H +#define HICN_PROTOCOL_TCP_H + +#include "../base.h" +#include "../common.h" +#include "../name.h" + +/* + * NOTE: bitfields are problematic for portability reasons. There are provided + * here for reference and documentation purposes, we might just provide a macro + * to disable and use it instead of __BYTE_ORDER__. + */ +typedef struct __attribute__ ((packed)) +{ + u16 sport; + u16 dport; + union + { + u32 seq; + hicn_name_suffix_t name_suffix; + }; + union + { + u32 seq_ack; + struct + { + hicn_pathlabel_t pathlabel; + u8 pad[3]; + }; + }; + + union + { + struct + { + u8 data_offset_and_reserved; + u8 flags; + }; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + struct + { + u16 reserved:4; + u16 doff:4; + u16 fin:1; + u16 syn:1; + u16 rst:1; + u16 psh:1; + u16 ack:1; + u16 urg:1; + u16 ece:1; + u16 cwr:1; + }; + struct + { /* __ denotes unchanged bitfields */ + u16 timescale:4; + u16 __doff:4; + u16 __fin:1; + u16 __syn:1; + u16 __rst:1; + u16 sig:1; + u16 __ack:1; + u16 man:1; + u16 id:1; + u16 __cwr:1; + }; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + struct + { + u16 doff:4; + u16 reserved:4; + u16 cwr:1; + u16 ece:1; + u16 urg:1; + u16 ack:1; + u16 psh:1; + u16 rst:1; + u16 syn:1; + u16 fin:1; + }; + struct + { + u16 __doff:4; + u16 timescale:4; + u16 __cwr:1; + u16 id:1 u16 man:1; + u16 __ack:1; + u16 sig:1; + u16 __rst:1; + u16 __syn:1; + u16 __fin:1; + }; +#endif + }; + union + { + u16 window; + u16 ldr; + }; + u16 csum; + union + { + u16 urg_ptr; + u16 lifetime; + }; +} _tcp_header_t; + +#define TCP_HDRLEN sizeof(_tcp_header_t) + +#ifndef HICN_VPP_PLUGIN + +/* TCP flags bit 0 first. */ +#define foreach_tcp_flag \ + _ (FIN) /**< No more data from sender. */ \ + _ (SYN) /**< Synchronize sequence numbers. */ \ + _ (RST) /**< Reset the connection. */ \ + _ (PSH) /**< Push function. */ \ + _ (ACK) /**< Ack field significant. */ \ + _ (URG) /**< Urgent pointer field significant. */ \ + _ (ECE) /**< ECN-echo. Receiver got CE packet */ \ + _ (CWR) /**< Sender reduced congestion window */ + +enum +{ +#define _(f) TCP_FLAG_BIT_##f, + foreach_tcp_flag +#undef _ + TCP_N_FLAG_BITS, +}; + +enum +{ +#define _(f) TCP_FLAG_##f = 1 << TCP_FLAG_BIT_##f, + foreach_tcp_flag +#undef _ +}; + +#endif /* HICN_VPP_PLUGIN */ + +// get_data_name_suffix +// name->ip4.suffix = h->v4.tcp.seq; + + +#endif /* HICN_PROTOCOL_TCP_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/lib/src/protocol/udp.h b/lib/src/protocol/udp.h new file mode 100755 index 000000000..58cd65095 --- /dev/null +++ b/lib/src/protocol/udp.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * 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. + */ + +#ifndef HICN_PROTOCOL_UDP_H +#define HICN_PROTOCOL_UDP_H + +typedef struct +{ + u16 src_port; + u16 dst_port; + u16 length; + u16 checksum; +} _udp_header_t; + +#define UDP_HDRLEN sizeof(_udp_header_t) + +#endif /* HICN_PROTOCOL_UDP_H */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |