From 9c30851b454fd4ecc253e1e6bb988e88a9ff4d79 Mon Sep 17 00:00:00 2001 From: Martine Lenders <mlenders@inf.fu-berlin.de> Date: Sat, 28 Mar 2015 14:05:17 +0100 Subject: [PATCH] ipv6_hdr: Initial import --- Makefile.dep | 5 + sys/Makefile | 3 + sys/include/net/ng_ipv6.h | 1 + sys/include/net/ng_ipv6/hdr.h | 324 ++++++++++++++++++ sys/net/network_layer/ng_ipv6/hdr/Makefile | 3 + .../network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c | 85 +++++ 6 files changed, 421 insertions(+) create mode 100644 sys/include/net/ng_ipv6/hdr.h create mode 100644 sys/net/network_layer/ng_ipv6/hdr/Makefile create mode 100644 sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c diff --git a/Makefile.dep b/Makefile.dep index 8a90097714..f63ce39e8d 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -48,6 +48,11 @@ ifneq (,$(filter sixlowpan,$(USEMODULE))) USEMODULE += vtimer endif +ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE))) + USEMODULE += ng_inet_csum + USEMODULE += ng_pktbuf +endif + ifneq (,$(filter ng_ipv6_nc,$(USEMODULE))) USEMODULE += ng_ipv6_addr endif diff --git a/sys/Makefile b/sys/Makefile index d7117e0286..b5b18b7a8d 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -65,6 +65,9 @@ endif ifneq (,$(filter ng_ipv6_addr,$(USEMODULE))) DIRS += net/network_layer/ng_ipv6/addr endif +ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE))) + DIRS += net/network_layer/ng_ipv6/hdr +endif ifneq (,$(filter ng_ipv6_nc,$(USEMODULE))) DIRS += net/network_layer/ng_ipv6/nc endif diff --git a/sys/include/net/ng_ipv6.h b/sys/include/net/ng_ipv6.h index 0b0086918f..7468121ce8 100644 --- a/sys/include/net/ng_ipv6.h +++ b/sys/include/net/ng_ipv6.h @@ -23,6 +23,7 @@ #define NG_IPV6_H_ #include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/hdr.h" #include "net/ng_ipv6/netif.h" #ifdef __cplusplus diff --git a/sys/include/net/ng_ipv6/hdr.h b/sys/include/net/ng_ipv6/hdr.h new file mode 100644 index 0000000000..3a18ba0646 --- /dev/null +++ b/sys/include/net/ng_ipv6/hdr.h @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ng_ipv6_hdr IPv6 header defintions + * @ingroup net_ng_ipv6 + * @{ + * + * @file + * @brief IPv6 header + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef NG_IPV6_HDR_H_ +#define NG_IPV6_HDR_H_ + +#include <inttypes.h> +#include <stdbool.h> + +#include "byteorder.h" +#include "net/ng_ipv6/addr.h" +#include "net/ng_inet_csum.h" +#include "net/ng_pkt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Data type to represent an IPv6 packet header + * + * @details The structure of the header is as follows: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.unparsed} + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| Traffic Class | Flow Label | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload Length | Next Header | Hop Limit | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Source Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Destination Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see <a href="http://tools.ietf.org/html/rfc2460#section-3"> + * RFC 2460, section 3 + * </a> + */ +typedef struct __attribute__((packed)) { + /** + * @brief Version, traffic class, and flow label + * + * @details The version are the 4 most significant bits, the traffic class + * the 8 next bit, and the remainding 20 bits are the flow label (see + * above). + * + * This module provides helper functions to set, get, and check these + * fields accordingly: + * * ng_ipv6_hdr_set_version() + * * ng_ipv6_hdr_get_version() + * * ng_ipv6_hdr_is_ipv6_hdr() + * * ng_ipv6_hdr_set_tc() + * * ng_ipv6_hdr_set_tc_ecn() + * * ng_ipv6_hdr_set_tc_dscp() + * * ng_ipv6_hdr_get_tc() + * * ng_ipv6_hdr_get_tc_ecn() + * * ng_ipv6_hdr_get_tc_dscp() + * * ng_ipv6_hdr_set_fl() + * * ng_ipv6_hdr_get_fl() + */ + network_uint32_t v_tc_fl; + network_uint16_t len; /**< payload length of this packet. */ + uint8_t nh; /**< type of next header in this packet. */ + uint8_t hl; /**< hop limit for this packet. */ + ng_ipv6_addr_t src; /**< source address of this packet. */ + ng_ipv6_addr_t dst; /**< destination address of this packet. */ +} ng_ipv6_hdr_t; + +/** + * @brief Sets the version field of @p hdr to 6 + * + * @param[out] hdr Pointer to an IPv6 header. + */ +static inline void ng_ipv6_hdr_set_version(ng_ipv6_hdr_t *hdr) +{ + hdr->v_tc_fl.u8[0] &= 0x0f; + hdr->v_tc_fl.u8[0] |= 0x60; +} + +/** + * @brief Gets the value of the version field of @p hdr + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the version field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_version(const ng_ipv6_hdr_t *hdr) +{ + return ((hdr->v_tc_fl.u8[0]) >> 4); +} + +/** + * @brief Checks if the version field is set to 6 + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return true, if version field is 6 + * @return false, otherwise + */ +static inline bool ng_ipv6_hdr_is_ipv6_hdr(const ng_ipv6_hdr_t *hdr) +{ + return (((hdr->v_tc_fl.u8[0]) & 0xf0) == 0x60); +} + +/** + * @brief Sets the traffic class field of @p hdr + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] tc The new value for the traffic class field. + */ +static inline void ng_ipv6_hdr_set_tc(ng_ipv6_hdr_t *hdr, uint8_t tc) +{ + hdr->v_tc_fl.u8[0] &= 0xf0; + hdr->v_tc_fl.u8[0] |= (0x0f & (tc >> 4)); + hdr->v_tc_fl.u8[1] &= 0x0f; + hdr->v_tc_fl.u8[1] |= (0xf0 & (tc << 4)); +} + +/** + * @brief Sets the value of the Explicit Congestion Notification (ECN) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see <a href="https://tools.ietf.org/html/rfc3168#section-5"> + * RFC 3168, section 5 + * </a> + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] ecn The new value for the 2-bit ECN part of the traffic class + * field. + */ +static inline void ng_ipv6_hdr_set_tc_ecn(ng_ipv6_hdr_t *hdr, uint8_t ecn) +{ + hdr->v_tc_fl.u8[0] &= 0xf3; + hdr->v_tc_fl.u8[0] |= (0x0c & (ecn << 2)); +} + +/** + * @brief Sets the value of the Differentiated Service Codepoint (DSCP) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see <a href="https://tools.ietf.org/html/rfc2474#section-3"> + * RFC 2474, section 3 + * </a> + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] dscp The new value for the 6-bit DSCP ng_part of the traffic class + * field. + */ +static inline void ng_ipv6_hdr_set_tc_dscp(ng_ipv6_hdr_t *hdr, uint8_t dscp) +{ + hdr->v_tc_fl.u8[0] &= 0xfc; + hdr->v_tc_fl.u8[0] |= (0x03 & (dscp >> 4)); + hdr->v_tc_fl.u8[1] &= 0x0f; + hdr->v_tc_fl.u8[1] |= (0xf0 & (dscp << 4)); +} + +/** + * @brief Gets the value of the traffic class field of @p hdr + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the traffic class field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_tc(const ng_ipv6_hdr_t *hdr) +{ + return ((((hdr->v_tc_fl.u8[0]) & 0x0f) << 4) | + ((hdr->v_tc_fl.u8[1] & 0xf0) >> 4)); +} + +/** + * @brief Gets the value of the Explicit Congestion Notification (ECN) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see <a href="https://tools.ietf.org/html/rfc3168#section-5"> + * RFC 3168, section 5 + * </a> + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the ECN part of the traffic class field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_tc_ecn(const ng_ipv6_hdr_t *hdr) +{ + return (((hdr->v_tc_fl.u8[0]) & 0x0c) >> 2); +} + + +/** + * @brief Gets the value of the Differentiated Service Codepoint (DSCP) part + * of the traffic class field of @p hdr + * + * @details The field is needed e.g. in context of 6LoWPAN header compression + * + * @see <a href="https://tools.ietf.org/html/rfc2474#section-3"> + * RFC 2474, section 3 + * </a> + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the DSCP part of the traffic class field of @p hdr. + */ +static inline uint8_t ng_ipv6_hdr_get_tc_dscp(const ng_ipv6_hdr_t *hdr) +{ + return ((((hdr->v_tc_fl.u8[0]) & 0x03) << 4) | + ((hdr->v_tc_fl.u8[1] & 0xf0) >> 4)); +} + +/** + * @brief Sets the flow label field of @p hdr + * + * @param[out] hdr Pointer to an IPv6 header. + * @param[in] fl The new value for the flow label field in host byte order. + */ +static inline void ng_ipv6_hdr_set_fl(ng_ipv6_hdr_t *hdr, uint32_t fl) +{ + hdr->v_tc_fl.u8[1] &= 0xf0; + hdr->v_tc_fl.u8[1] |= (0x0f & (byteorder_htonl(fl).u8[1])); + hdr->v_tc_fl.u16[1] = byteorder_htonl(fl).u16[1]; +} + +/** + * @brief Gets the value of the flow label field of @p hdr + * + * @param[in] hdr Pointer to an IPv6 header. + * + * @return Value of the flow label field of @p hdr. + */ +static inline uint32_t ng_ipv6_hdr_get_fl(const ng_ipv6_hdr_t *hdr) +{ + return byteorder_ntohl(hdr->v_tc_fl) & 0x000fffff; +} + +/** + * @brief Calculates the Internet Checksum for the IPv6 Pseudo Header. + * + * @see <a href="https://tools.ietf.org/html/rfc2460#section-8.1"> + * RFC 2460, section 8.1 + * </a> + * + * @param[in] sum Preinialized value of the sum. + * @param[in] prot_num The @ref net_ng_protnum you want to calculate the + * checksum for. Can not be inferred from + * ng_ipv6_hdr_t::nh, since it can be an IPv6 exentension + * header. + * @param[in] hdr An IPv6 header to derive the Pseudo Header from. + * @param[in] len The upper-layer packet length for the pseudo header. + * Can not be inferred from ng_ipv6_hdr_t::len, since + * there can be extension headers between the IPv6 header + * and the payload. + * + * @return The non-normalized Internet Checksum of the given IPv6 pseudo header. + */ +static inline uint16_t ng_ipv6_hdr_inet_csum(uint16_t sum, ng_ipv6_hdr_t *hdr, + uint8_t prot_num, uint16_t len) +{ + return ng_inet_csum(sum + len + prot_num, hdr->src.u8, + (2 * sizeof(ng_ipv6_addr_t))); +} + +/** + * @brief Builds an IPv6 header for sending and adds it to the packet buffer. + * + * @details Initializes version field with 6, traffic class, flow label, and + * hop limit with 0, and next header with @ref NG_PROTNUM_RESERVED. + * + * @param[in] payload Payload for the packet. + * @param[in] src Source address for the header. Can be NULL if not + * known or required. + * @param[in] src_len Length of @p src. Can be 0 if not known or required or + * must be `sizeof(ng_ipv6_addr_t)`. + * @param[in] dst Destination address for the header. Can be NULL if not + * known or required. + * @param[in] dst_len Length of @p dst. Can be 0 if not known or required or + * must be `sizeof(ng_ipv6_addr_t)`. + * + * @return The an IPv6 header in packet buffer on success. + * @return NULL on error. + */ +ng_pktsnip_t *ng_ipv6_hdr_build(ng_pktsnip_t *payload, + uint8_t *src, uint8_t src_len, + uint8_t *dst, uint8_t dst_len); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_IPV6_HDR_H_ */ +/** @} */ diff --git a/sys/net/network_layer/ng_ipv6/hdr/Makefile b/sys/net/network_layer/ng_ipv6/hdr/Makefile new file mode 100644 index 0000000000..204e78e385 --- /dev/null +++ b/sys/net/network_layer/ng_ipv6/hdr/Makefile @@ -0,0 +1,3 @@ +MODULE = ng_ipv6_hdr + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c b/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c new file mode 100644 index 0000000000..9804b72308 --- /dev/null +++ b/sys/net/network_layer/ng_ipv6/hdr/ng_ipv6_hdr.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + */ + +#include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/hdr.h" +#include "net/ng_nettype.h" +#include "net/ng_pktbuf.h" +#include "net/ng_protnum.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if ENABLE_DEBUG && defined(MODULE_NG_IPV6_ADDR) +static char addr_str[NG_IPV6_ADDR_MAX_STR_LEN]; +#endif + +/* For independent testing */ +#ifdef MODULE_NG_IPV6 +#define HDR_NETTYPE (NG_NETTYPE_IPV6) +#else +#define HDR_NETTYPE (NG_NETTYPE_UNDEF) +#endif + +ng_pktsnip_t *ng_ipv6_hdr_build(ng_pktsnip_t *payload, + uint8_t *src, uint8_t src_len, + uint8_t *dst, uint8_t dst_len) +{ + ng_pktsnip_t *ipv6; + ng_ipv6_hdr_t *hdr; + + if (((src_len != 0) && (src_len != sizeof(ng_ipv6_addr_t))) || + ((dst_len != 0) && (dst_len != sizeof(ng_ipv6_addr_t)))) { + DEBUG("ipv6_hdr: Address length was not 0 or %zu byte.\n", + sizeof(ng_ipv6_addr_t)); + return NULL; + } + + ipv6 = ng_pktbuf_add(payload, NULL, sizeof(ng_ipv6_hdr_t), HDR_NETTYPE); + + if (ipv6 == NULL) { + DEBUG("ipv6_hdr: no space left in packet buffer\n"); + return NULL; + } + + hdr = (ng_ipv6_hdr_t *)ipv6->data; + + if ((src != NULL) && (src_len != 0)) { +#ifdef MODULE_NG_IPV6_ADDR + DEBUG("ipv6_hdr: set packet source to %s\n", + ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)src, + sizeof(addr_str))); +#endif + memcpy(&hdr->src, src, src_len); + } + + memset(&hdr->dst + dst_len, 0, sizeof(ng_ipv6_addr_t) - dst_len); + + if ((dst != NULL) && (dst_len != 0)) { +#ifdef MODULE_NG_IPV6_ADDR + DEBUG("ipv6_hdr: set packet destination to %s\n", + ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)dst, + sizeof(addr_str))); +#endif + memcpy(&hdr->dst, dst, dst_len); + } + + hdr->v_tc_fl = byteorder_htonl(0x60000000); /* set version, tc and fl in one go*/ + hdr->nh = NG_PROTNUM_RESERVED; + hdr->hl = 0; + + return ipv6; +} + +/** @} */ -- GitLab