1 // SPDX-License-Identifier: LGPL-2.1-or-later
3 * This file is part of the PCEPlib, a PCEP protocol library.
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
7 * Author : Brady Johnson <brady@voltanet.io>
13 * Encoding and decoding for PCEP messages.
24 #include "pcep_msg_encoding.h"
25 #include "pcep_msg_messages.h"
26 #include "pcep_msg_objects.h"
27 #include "pcep_msg_tools.h"
28 #include "pcep_utils_logging.h"
29 #include "pcep_utils_memory.h"
33 #define NUM_CHECKED_OBJECTS 4
34 /* It wont compile with this definition:
36 MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS]
38 static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES
[13][4] =
40 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
41 NO_OBJECT
}, /* unsupported message ID = 0 */
42 {PCEP_OBJ_CLASS_OPEN
, NO_OBJECT
, NO_OBJECT
,
43 NO_OBJECT
}, /* PCEP_TYPE_OPEN = 1 */
44 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
45 NO_OBJECT
}, /* PCEP_TYPE_KEEPALIVE = 2 */
46 {PCEP_OBJ_CLASS_RP
, PCEP_OBJ_CLASS_ENDPOINTS
, ANY_OBJECT
,
47 ANY_OBJECT
}, /* PCEP_TYPE_PCREQ = 3 */
48 {PCEP_OBJ_CLASS_RP
, ANY_OBJECT
, ANY_OBJECT
,
49 ANY_OBJECT
}, /* PCEP_TYPE_PCREP = 4 */
50 {PCEP_OBJ_CLASS_NOTF
, ANY_OBJECT
, ANY_OBJECT
,
51 ANY_OBJECT
}, /* PCEP_TYPE_PCNOTF = 5 */
52 {PCEP_OBJ_CLASS_ERROR
, ANY_OBJECT
, ANY_OBJECT
,
53 ANY_OBJECT
}, /* PCEP_TYPE_ERROR = 6 */
54 {PCEP_OBJ_CLASS_CLOSE
, NO_OBJECT
, NO_OBJECT
,
55 NO_OBJECT
}, /* PCEP_TYPE_CLOSE = 7 */
56 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
57 NO_OBJECT
}, /* unsupported message ID = 8 */
58 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
59 NO_OBJECT
}, /* unsupported message ID = 9 */
60 {PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_CLASS_LSP
, ANY_OBJECT
,
61 ANY_OBJECT
}, /* PCEP_TYPE_REPORT = 10 */
62 {PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_CLASS_LSP
, ANY_OBJECT
,
63 ANY_OBJECT
}, /* PCEP_TYPE_UPDATE = 11 */
64 {PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_CLASS_LSP
, ANY_OBJECT
,
65 ANY_OBJECT
}, /* PCEP_TYPE_INITIATE = 12 */
68 /* PCEP Message Common Header, According to RFC 5440
71 * 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
72 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 * | Ver | Flags | Message-Type | Message-Length |
74 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 * Ver (Version - 3 bits): PCEP version number. Current version is version 1.
78 * Flags (5 bits): No flags are currently defined. Unassigned bits are
79 * considered as reserved. They MUST be set to zero on transmission
80 * and MUST be ignored on receipt.
82 void pcep_encode_message(struct pcep_message
*message
,
83 struct pcep_versioning
*versioning
)
85 if (message
== NULL
) {
89 if (message
->msg_header
== NULL
) {
93 /* Internal buffer used for the entire message. Later, once the entire
94 * length is known, memory will be allocated and this buffer will be
96 uint8_t message_buffer
[PCEP_MESSAGE_LENGTH
] = {0};
98 /* Write the message header. The message header length will be
99 * written when the entire length is known. */
100 uint32_t message_length
= MESSAGE_HEADER_LENGTH
;
101 uint16_t net_order_length
= 0;
102 message_buffer
[0] = (message
->msg_header
->pcep_version
<< 5) & 0xf0;
103 message_buffer
[1] = message
->msg_header
->type
;
105 if (message
->obj_list
== NULL
) {
106 net_order_length
= htons(message_length
);
107 memcpy(message_buffer
+ 2, &net_order_length
,
108 sizeof(net_order_length
));
109 message
->encoded_message
=
110 pceplib_malloc(PCEPLIB_MESSAGES
, message_length
);
111 memcpy(message
->encoded_message
, message_buffer
,
113 message
->encoded_message_length
= message_length
;
118 /* Encode each of the objects */
119 double_linked_list_node
*node
= message
->obj_list
->head
;
120 for (; node
!= NULL
; node
= node
->next_node
) {
122 pcep_encode_object(node
->data
, versioning
,
123 message_buffer
+ message_length
);
124 if (message_length
>= PCEP_MESSAGE_LENGTH
) {
125 message
->encoded_message
= NULL
;
126 message
->encoded_message_length
= 0;
131 net_order_length
= htons(message_length
);
132 memcpy(message_buffer
+ 2, &net_order_length
, sizeof(net_order_length
));
133 message
->encoded_message
=
134 pceplib_malloc(PCEPLIB_MESSAGES
, message_length
);
135 memcpy(message
->encoded_message
, message_buffer
, message_length
);
136 message
->encoded_message_length
= message_length
;
143 /* Expecting Host byte ordered header */
144 static bool validate_msg_header(uint8_t msg_version
, uint8_t msg_flags
,
145 uint8_t msg_type
, uint16_t msg_length
)
147 /* Invalid message if the length is less than the header
148 * size or if its not a multiple of 4 */
149 if (msg_length
< MESSAGE_HEADER_LENGTH
|| (msg_length
% 4) != 0) {
151 "%s: Invalid PCEP message header length [%d]",
152 __func__
, msg_length
);
156 if (msg_version
!= PCEP_MESSAGE_HEADER_VERSION
) {
159 "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]",
160 __func__
, msg_version
, PCEP_MESSAGE_HEADER_VERSION
);
164 if (msg_flags
!= 0) {
166 "%s: Invalid PCEP message header flags [0x%x]",
167 __func__
, msg_flags
);
172 /* Supported message types */
174 case PCEP_TYPE_KEEPALIVE
:
175 case PCEP_TYPE_PCREQ
:
176 case PCEP_TYPE_PCREP
:
177 case PCEP_TYPE_PCNOTF
:
178 case PCEP_TYPE_ERROR
:
179 case PCEP_TYPE_CLOSE
:
180 case PCEP_TYPE_REPORT
:
181 case PCEP_TYPE_UPDATE
:
182 case PCEP_TYPE_INITIATE
:
185 pcep_log(LOG_INFO
, "%s: Invalid PCEP message header type [%d]",
194 /* Internal util function */
195 static uint16_t pcep_decode_msg_header(const uint8_t *msg_buf
,
196 uint8_t *msg_version
, uint8_t *msg_flags
,
199 // Check RFC 5440 for version and flags position.
200 // 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
201 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202 //| Ver | Flags | Message-Type | Message-Length |
203 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204 *msg_version
= (msg_buf
[0] >> 5) & 0x07;
205 *msg_flags
= (msg_buf
[0] & 0x1f);
206 *msg_type
= msg_buf
[1];
207 uint16_t host_order_length
;
208 memcpy(&host_order_length
, msg_buf
+ 2, sizeof(host_order_length
));
209 return ntohs(host_order_length
);
212 /* Decode the message header and return the message length */
213 int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf
)
220 msg_length
= pcep_decode_msg_header(msg_buf
, &msg_version
, &msg_flags
,
223 return ((validate_msg_header(msg_version
, msg_flags
, msg_type
,
227 : (int32_t)msg_length
);
230 bool validate_message_objects(struct pcep_message
*msg
)
232 if (msg
->msg_header
->type
>= PCEP_TYPE_START_TLS
) {
235 "%s: Rejecting received message: Unknown message type [%d]",
236 __func__
, msg
->msg_header
->type
);
240 const enum pcep_object_classes
*object_classes
=
241 MANDATORY_MESSAGE_OBJECT_CLASSES
[msg
->msg_header
->type
];
242 double_linked_list_node
*node
;
244 for (node
= (msg
->obj_list
== NULL
? NULL
: msg
->obj_list
->head
),
246 index
< NUM_CHECKED_OBJECTS
;
247 index
++, (node
= (node
== NULL
? NULL
: node
->next_node
))) {
248 struct pcep_object_header
*obj
=
251 : (struct pcep_object_header
*)node
->data
);
253 if ((int)object_classes
[index
] == NO_OBJECT
) {
257 "%s: Rejecting received message: Unexpected object [%d] present",
258 __func__
, obj
->object_class
);
261 } else if (object_classes
[index
] != ANY_OBJECT
) {
265 "%s: Rejecting received message: Expecting object in position [%d], but none received",
268 } else if (object_classes
[index
] != obj
->object_class
) {
271 "%s: Rejecting received message: Unexpected Object Class received [%d]",
272 __func__
, object_classes
[index
]);
281 struct pcep_message
*pcep_decode_message(const uint8_t *msg_buf
)
288 msg_length
= pcep_decode_msg_header(msg_buf
, &msg_version
, &msg_flags
,
290 if (msg_length
== 0) {
291 pcep_log(LOG_INFO
, "%s: Discarding empty message", __func__
);
294 if (msg_length
>= PCEP_MESSAGE_LENGTH
) {
295 pcep_log(LOG_INFO
, "%s: Discarding message too big", __func__
);
299 struct pcep_message
*msg
=
300 pceplib_calloc(PCEPLIB_MESSAGES
, sizeof(struct pcep_message
));
302 msg
->msg_header
= pceplib_malloc(PCEPLIB_MESSAGES
,
303 sizeof(struct pcep_message_header
));
304 msg
->msg_header
->pcep_version
= msg_version
;
305 msg
->msg_header
->type
= msg_type
;
307 msg
->obj_list
= dll_initialize();
308 msg
->encoded_message
= pceplib_malloc(PCEPLIB_MESSAGES
, msg_length
);
309 memcpy(msg
->encoded_message
, msg_buf
, msg_length
);
310 msg
->encoded_message_length
= msg_length
;
312 uint16_t bytes_read
= MESSAGE_HEADER_LENGTH
;
313 while ((msg_length
- bytes_read
) >= OBJECT_HEADER_LENGTH
) {
314 struct pcep_object_header
*obj_hdr
=
315 pcep_decode_object(msg_buf
+ bytes_read
);
317 if (obj_hdr
== NULL
) {
318 pcep_log(LOG_INFO
, "%s: Discarding invalid message",
320 pcep_msg_free_message(msg
);
325 dll_append(msg
->obj_list
, obj_hdr
);
326 bytes_read
+= obj_hdr
->encoded_object_length
;
329 if (validate_message_objects(msg
) == false) {
330 pcep_log(LOG_INFO
, "%s: Discarding invalid message", __func__
);
331 pcep_msg_free_message(msg
);
339 struct pcep_versioning
*create_default_pcep_versioning(void)
341 struct pcep_versioning
*versioning
=
342 pceplib_malloc(PCEPLIB_INFRA
, sizeof(struct pcep_versioning
));
343 memset(versioning
, 0, sizeof(struct pcep_versioning
));
348 void destroy_pcep_versioning(struct pcep_versioning
*versioning
)
350 pceplib_free(PCEPLIB_INFRA
, versioning
);