/*
* This file is part of the PCEPlib, a PCEP protocol library.
*
* Copyright (C) 2020 Volta Networks https://voltanet.io/
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Author : Brady Johnson
*
*/
/*
* This is the implementation of a High Level PCEP message API.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include
#include
#include
#include
#include "pcep_msg_encoding.h"
#include "pcep_msg_messages.h"
#include "pcep_msg_objects.h"
#include "pcep_utils_double_linked_list.h"
#include "pcep_utils_logging.h"
#include "pcep_utils_memory.h"
static struct pcep_message *
pcep_msg_create_common_with_obj_list(enum pcep_message_types msg_type,
double_linked_list *obj_list)
{
struct pcep_message *message =
pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
memset(message, 0, sizeof(struct pcep_message));
message->msg_header = pceplib_malloc(
PCEPLIB_MESSAGES, sizeof(struct pcep_message_header));
memset(message->msg_header, 0, sizeof(struct pcep_message_header));
message->msg_header->type = msg_type;
message->msg_header->pcep_version = PCEP_MESSAGE_HEADER_VERSION;
message->obj_list = ((obj_list == NULL) ? dll_initialize() : obj_list);
return message;
}
static struct pcep_message *
pcep_msg_create_common(enum pcep_message_types msg_type)
{
return pcep_msg_create_common_with_obj_list(msg_type, NULL);
}
struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer,
uint8_t sid)
{
struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN);
dll_append(message->obj_list,
pcep_obj_create_open(keepalive, deadtimer, sid, NULL));
return message;
}
struct pcep_message *
pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer,
uint8_t sid, double_linked_list *tlv_list)
{
struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN);
dll_append(message->obj_list,
pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list));
return message;
}
struct pcep_message *
pcep_msg_create_request(struct pcep_object_rp *rp,
struct pcep_object_endpoints_ipv4 *endpoints,
double_linked_list *object_list)
{
if ((rp == NULL) || (endpoints == NULL)) {
return NULL;
}
struct pcep_message *message = pcep_msg_create_common_with_obj_list(
PCEP_TYPE_PCREQ, object_list);
dll_prepend(message->obj_list, endpoints);
dll_prepend(message->obj_list, rp);
return message;
}
struct pcep_message *
pcep_msg_create_request_ipv6(struct pcep_object_rp *rp,
struct pcep_object_endpoints_ipv6 *endpoints,
double_linked_list *object_list)
{
if ((rp == NULL) || (endpoints == NULL)) {
return NULL;
}
struct pcep_message *message = pcep_msg_create_common_with_obj_list(
PCEP_TYPE_PCREQ, object_list);
dll_prepend(message->obj_list, endpoints);
dll_prepend(message->obj_list, rp);
return message;
}
struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp,
double_linked_list *object_list)
{
struct pcep_message *message = pcep_msg_create_common_with_obj_list(
PCEP_TYPE_PCREP, object_list);
if (rp != NULL) {
dll_prepend(message->obj_list, rp);
}
return message;
}
struct pcep_message *pcep_msg_create_close(uint8_t reason)
{
struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_CLOSE);
dll_append(message->obj_list, pcep_obj_create_close(reason));
return message;
}
struct pcep_message *pcep_msg_create_error(uint8_t error_type,
uint8_t error_value)
{
struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_ERROR);
dll_append(message->obj_list,
pcep_obj_create_error(error_type, error_value));
return message;
}
struct pcep_message *
pcep_msg_create_error_with_objects(uint8_t error_type, uint8_t error_value,
double_linked_list *object_list)
{
struct pcep_message *message = pcep_msg_create_common_with_obj_list(
PCEP_TYPE_ERROR, object_list);
dll_prepend(message->obj_list,
pcep_obj_create_error(error_type, error_value));
return message;
}
struct pcep_message *pcep_msg_create_keepalive()
{
return (pcep_msg_create_common(PCEP_TYPE_KEEPALIVE));
}
struct pcep_message *
pcep_msg_create_report(double_linked_list *state_report_object_list)
{
return (state_report_object_list == NULL
? NULL
: pcep_msg_create_common_with_obj_list(
PCEP_TYPE_REPORT, state_report_object_list));
}
struct pcep_message *
pcep_msg_create_update(double_linked_list *update_request_object_list)
{
if (update_request_object_list == NULL) {
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_update NULL update_request_object_list",
__func__);
return NULL;
}
/* There must be at least 3 objects:
* These 3 are mandatory: SRP, LSP, and ERO. The ERO may be empty */
if (update_request_object_list->num_entries < 3) {
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_update there must be at least 3 update objects",
__func__);
return NULL;
}
double_linked_list_node *node = update_request_object_list->head;
struct pcep_object_header *obj_hdr =
(struct pcep_object_header *)node->data;
/* Check for the mandatory first SRP object */
if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) {
/* If the SRP object is missing, the receiving PCC MUST send a
* PCErr message with Error-type=6 (Mandatory Object missing)
* and Error-value=10 (SRP object missing). */
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_update missing mandatory first SRP object",
__func__);
return NULL;
}
/* Check for the mandatory 2nd LSP object */
node = node->next_node;
obj_hdr = (struct pcep_object_header *)node->data;
if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) {
/* If the LSP object is missing, the receiving PCC MUST send a
* PCErr message with Error-type=6 (Mandatory Object missing)
* and Error-value=8 (LSP object missing). */
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_update missing mandatory second LSP object",
__func__);
return NULL;
}
/* Check for the mandatory 3rd ERO object */
node = node->next_node;
obj_hdr = (struct pcep_object_header *)node->data;
if (obj_hdr->object_class != PCEP_OBJ_CLASS_ERO) {
/* If the ERO object is missing, the receiving PCC MUST send a
* PCErr message with Error-type=6 (Mandatory Object missing)
* and Error-value=9 (ERO object missing). */
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_update missing mandatory third ERO object",
__func__);
return NULL;
}
return (pcep_msg_create_common_with_obj_list(
PCEP_TYPE_UPDATE, update_request_object_list));
}
struct pcep_message *
pcep_msg_create_initiate(double_linked_list *lsp_object_list)
{
if (lsp_object_list == NULL) {
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_initiate NULL update_request_object_list",
__func__);
return NULL;
}
/* There must be at least 2 objects: SRP and LSP. */
if (lsp_object_list->num_entries < 2) {
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_initiate there must be at least 2 objects",
__func__);
return NULL;
}
double_linked_list_node *node = lsp_object_list->head;
struct pcep_object_header *obj_hdr =
(struct pcep_object_header *)node->data;
/* Check for the mandatory first SRP object */
if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) {
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_initiate missing mandatory first SRP object",
__func__);
return NULL;
}
/* Check for the mandatory 2nd LSP object */
node = node->next_node;
obj_hdr = (struct pcep_object_header *)node->data;
if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) {
pcep_log(
LOG_INFO,
"%s: pcep_msg_create_initiate missing mandatory second LSP object",
__func__);
return NULL;
}
return (pcep_msg_create_common_with_obj_list(PCEP_TYPE_INITIATE,
lsp_object_list));
}
struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify,
double_linked_list *object_list)
{
if (notify == NULL) {
pcep_log(LOG_INFO,
"%s: pcep_msg_create_notify NULL notify object",
__func__);
return NULL;
}
struct pcep_message *message = pcep_msg_create_common_with_obj_list(
PCEP_TYPE_PCNOTF, object_list);
dll_prepend(message->obj_list, notify);
return message;
}