/*
 * Copyright (c) 2013-2018, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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 _ICMPV6_H
#define _ICMPV6_H
#include "Common_Protocols/icmpv6_prefix.h"

#define ICMPV6_TYPE_ERROR_DESTINATION_UNREACH       1
#define ICMPV6_TYPE_ERROR_PACKET_TOO_BIG            2
#define ICMPV6_TYPE_ERROR_TIME_EXCEEDED             3
#define ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM         4

#define ICMPV6_TYPE_INFO_ECHO_REQUEST               128
#define ICMPV6_TYPE_INFO_ECHO_REPLY                 129
#define ICMPV6_TYPE_INFO_MCAST_LIST_QUERY           130
#define ICMPV6_TYPE_INFO_MCAST_LIST_REPORT          131
#define ICMPV6_TYPE_INFO_MCAST_LIST_DONE            132
#define ICMPV6_TYPE_INFO_RS                         133
#define ICMPV6_TYPE_INFO_RA                         134
#define ICMPV6_TYPE_INFO_NS                         135
#define ICMPV6_TYPE_INFO_NA                         136
#define ICMPV6_TYPE_INFO_REDIRECT                   137
#define ICMPV6_TYPE_INFO_MCAST_LIST_REPORT_V2       143
#define ICMPV6_TYPE_INFO_RPL_CONTROL                155
#define ICMPV6_TYPE_INFO_DAR                        157
#define ICMPV6_TYPE_INFO_DAC                        158
#define ICMPV6_TYPE_INFO_MPL_CONTROL                159

#define ICMPV6_CODE_DST_UNREACH_NO_ROUTE            0
#define ICMPV6_CODE_DST_UNREACH_ADM_PROHIB          1
#define ICMPV6_CODE_DST_UNREACH_BEYOND_SCOPE        2
#define ICMPV6_CODE_DST_UNREACH_ADDR_UNREACH        3
#define ICMPV6_CODE_DST_UNREACH_PORT_UNREACH        4
#define ICMPV6_CODE_DST_UNREACH_SRC_FAILED_POLICY   5
#define ICMPV6_CODE_DST_UNREACH_ROUTE_REJECTED      6
#define ICMPV6_CODE_DST_UNREACH_SRC_RTE_HDR_ERR     7

#define ICMPV6_CODE_TME_EXCD_HOP_LIM_EXCD           0
#define ICMPV6_CODE_TME_EXCD_FRG_REASS_TME_EXCD     1

#define ICMPV6_CODE_PARAM_PRB_HDR_ERR               0
#define ICMPV6_CODE_PARAM_PRB_UNREC_NEXT_HDR        1
#define ICMPV6_CODE_PARAM_PRB_UNREC_IPV6_OPT        2
#define ICMPV6_CODE_PARAM_PRB_FIRST_FRAG_IPV6_HDR   3

#define ICMPV6_CODE_RPL_DIS                         0x00
#define ICMPV6_CODE_RPL_DIO                         0x01
#define ICMPV6_CODE_RPL_DAO                         0x02
#define ICMPV6_CODE_RPL_DAO_ACK                     0x03
#define ICMPV6_CODE_RPL_P2P_DRO                     0x04
#define ICMPV6_CODE_RPL_P2P_DRO_ACK                 0x05
#define ICMPV6_CODE_RPL_SECURE_DIS                  0x80
#define ICMPV6_CODE_RPL_SECURE_DIO                  0x81
#define ICMPV6_CODE_RPL_SECURE_DAO                  0x82
#define ICMPV6_CODE_RPL_SECURE_DAO_ACK              0x83
#define ICMPV6_CODE_RPL_SECURE_P2P_DRO              0x84
#define ICMPV6_CODE_RPL_SECURE_P2P_DRO_ACK          0x85
#define ICMPV6_CODE_RPL_CC                          0x8A

/* Options in ICMPv6 Neighbor Discovery Protocol (RPL has totally different options...) */
#define ICMPV6_OPT_SRC_LL_ADDR                      1
#define ICMPV6_OPT_TGT_LL_ADDR                      2
#define ICMPV6_OPT_PREFIX_INFO                      3
#define ICMPV6_OPT_REDIRECTED_HDR                   4
#define ICMPV6_OPT_MTU                              5
#define ICMPV6_OPT_ROUTE_INFO                       24
#define ICMPV6_OPT_RECURSIVE_DNS_SERVER             25
#define ICMPV6_OPT_DNS_SEARCH_LIST                  31
#define ICMPV6_OPT_ADDR_REGISTRATION                33
#define ICMPV6_OPT_6LOWPAN_CONTEXT                  34
#define ICMPV6_OPT_AUTHORITATIVE_BORDER_RTR         35

/* Neighbour Advertisement flags */
#define NA_R    0x80
#define NA_S    0x40
#define NA_O    0x20

/* Router Advertisement flags */
#define RA_M            0x80    // Managed
#define RA_O            0x40    // Other Configuration
#define RA_H            0x20    // Home Agent (RFC 6275)
#define RA_PRF_MASK     0x18    // Router Preference (RFC 4191)
#define RA_PRF_LOW      0x18    // (RA_PRF_xxx also occurs in Route Info Options)
#define RA_PRF_MEDIUM   0x00
#define RA_PRF_HIGH     0x08
#define RA_PRF_INVALID  0x10

struct buffer;
struct protocol_interface_info_entry;

typedef struct aro {
    uint16_t lifetime;
    uint8_t status;
    uint8_t eui64[8];
    bool present;
} aro_t;

typedef enum slaac_src {
    SLAAC_IID_DEFAULT,      // OPAQUE if key available and enabled on interface, else FIXED
    SLAAC_IID_EUI64,        // use fixed IID based on EUI-64/MAC-64 (iid_eui64)
    SLAAC_IID_FIXED,        // use fixed IID (iid_slaac)
    SLAAC_IID_OPAQUE,       // RFC 7217 opaque
    SLAAC_IID_6LOWPAN_SHORT // use IID based on 6LoWPAN short address
} slaac_src_e;

#define ARO_SUCCESS     0
#define ARO_DUPLICATE   1
#define ARO_FULL        2
#define ARO_TOPOLOGICALLY_INCORRECT 8

extern void icmpv6_init(void);
extern struct buffer *icmpv6_down(struct buffer *buf);
extern struct buffer *icmpv6_up(struct buffer *buf);
extern struct buffer *icmpv6_error(struct buffer *buf, struct protocol_interface_info_entry *cur, uint8_t type, uint8_t code, uint32_t aux);

extern bool icmpv6_options_well_formed(const uint8_t *dptr, uint_fast16_t dlen);
extern bool icmpv6_options_well_formed_in_buffer(const struct buffer *buf, uint16_t offset);
extern const uint8_t *icmpv6_find_option(const uint8_t *dptr, uint_fast16_t dlen, uint8_t option, uint8_t optlen);
extern const uint8_t *icmpv6_find_option_in_buffer(const struct buffer *buf, uint_fast16_t offset, uint8_t option, uint8_t optlen);

struct protocol_interface_info_entry;

extern struct buffer *icmpv6_build_rs(struct protocol_interface_info_entry *cur, const uint8_t *dest_addr);
extern struct buffer *icmpv6_build_ns(struct protocol_interface_info_entry *cur, const uint8_t target_addr[static 16], const uint8_t *prompting_src_addr, bool unicast, bool unspecified_source, const struct aro *aro);
extern struct buffer *icmpv6_build_na(struct protocol_interface_info_entry *cur, bool solicited, bool override, bool tllao_required, const uint8_t target[static 16], const aro_t *aro, const uint8_t src_addr[static 16]);
extern struct buffer *icmpv6_build_dad(struct protocol_interface_info_entry *cur, struct buffer *buf, uint8_t type, const uint8_t dest_addr[16], const uint8_t eui64[8], const uint8_t reg_addr[16], uint8_t status, uint16_t lifetime);
extern void icmpv6_build_echo_req(struct protocol_interface_info_entry *cur, const uint8_t target_addr[16]);

extern void icmpv6_recv_ra_routes(struct protocol_interface_info_entry *cur, bool enable);
extern void icmpv6_recv_ra_prefixes(struct protocol_interface_info_entry *cur, bool enable);

extern void icmpv6_slaac_prefix_register_trig(struct protocol_interface_info_entry *cur, uint8_t *prefix_ptr, uint8_t prefix_len);
extern int icmpv6_slaac_prefix_update(struct protocol_interface_info_entry *cur, const uint8_t *prefix_ptr, uint8_t prefix_len, uint32_t valid_lifetime, uint32_t preferred_lifetime);
extern struct if_address_entry *icmpv6_slaac_address_add(struct protocol_interface_info_entry *cur, const uint8_t *prefix_ptr, uint8_t prefix_len, uint32_t valid_lifetime, uint32_t preferred_lifetime, bool skip_dad, slaac_src_e slaac_src);


/*
 * Write either an ICMPv6 Prefix Information Option for a Router Advertisement
 * (RFC4861+6275), or an RPL Prefix Information Option (RFC6550).
 * Same payload, different type/len.
 */
uint8_t *icmpv6_write_prefix_option(const prefix_list_t *prefixes,  uint8_t *dptr, uint8_t rpl_prefix, struct protocol_interface_info_entry *cur);
uint8_t *icmpv6_write_mtu_option(uint32_t mtu, uint8_t *dptr);
uint8_t *icmpv6_write_icmp_lla(struct protocol_interface_info_entry *cur, uint8_t *dptr, uint8_t icmp_opt, bool must, const uint8_t *ip_addr);

#endif /* _ICMPV6_H */
