2 * This file is part of the PCEPlib, a PCEP protocol library.
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * Author : Brady Johnson <brady@voltanet.io>
25 * Encoding and decoding for PCEP messages.
36 #include "pcep_msg_encoding.h"
37 #include "pcep_msg_messages.h"
38 #include "pcep_msg_objects.h"
39 #include "pcep_msg_tools.h"
40 #include "pcep_utils_logging.h"
41 #include "pcep_utils_memory.h"
45 #define NUM_CHECKED_OBJECTS 4
46 /* It wont compile with this definition:
48 MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS]
50 static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES
[13][4] =
52 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
53 NO_OBJECT
}, /* unsupported message ID = 0 */
54 {PCEP_OBJ_CLASS_OPEN
, NO_OBJECT
, NO_OBJECT
,
55 NO_OBJECT
}, /* PCEP_TYPE_OPEN = 1 */
56 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
57 NO_OBJECT
}, /* PCEP_TYPE_KEEPALIVE = 2 */
58 {PCEP_OBJ_CLASS_RP
, PCEP_OBJ_CLASS_ENDPOINTS
, ANY_OBJECT
,
59 ANY_OBJECT
}, /* PCEP_TYPE_PCREQ = 3 */
60 {PCEP_OBJ_CLASS_RP
, ANY_OBJECT
, ANY_OBJECT
,
61 ANY_OBJECT
}, /* PCEP_TYPE_PCREP = 4 */
62 {PCEP_OBJ_CLASS_NOTF
, ANY_OBJECT
, ANY_OBJECT
,
63 ANY_OBJECT
}, /* PCEP_TYPE_PCNOTF = 5 */
64 {PCEP_OBJ_CLASS_ERROR
, ANY_OBJECT
, ANY_OBJECT
,
65 ANY_OBJECT
}, /* PCEP_TYPE_ERROR = 6 */
66 {PCEP_OBJ_CLASS_CLOSE
, NO_OBJECT
, NO_OBJECT
,
67 NO_OBJECT
}, /* PCEP_TYPE_CLOSE = 7 */
68 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
69 NO_OBJECT
}, /* unsupported message ID = 8 */
70 {NO_OBJECT
, NO_OBJECT
, NO_OBJECT
,
71 NO_OBJECT
}, /* unsupported message ID = 9 */
72 {PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_CLASS_LSP
, ANY_OBJECT
,
73 ANY_OBJECT
}, /* PCEP_TYPE_REPORT = 10 */
74 {PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_CLASS_LSP
, ANY_OBJECT
,
75 ANY_OBJECT
}, /* PCEP_TYPE_UPDATE = 11 */
76 {PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_CLASS_LSP
, ANY_OBJECT
,
77 ANY_OBJECT
}, /* PCEP_TYPE_INITIATE = 12 */
80 /* PCEP Message Common Header, According to RFC 5440
83 * 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
84 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85 * | Ver | Flags | Message-Type | Message-Length |
86 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88 * Ver (Version - 3 bits): PCEP version number. Current version is version 1.
90 * Flags (5 bits): No flags are currently defined. Unassigned bits are
91 * considered as reserved. They MUST be set to zero on transmission
92 * and MUST be ignored on receipt.
94 void pcep_encode_message(struct pcep_message
*message
,
95 struct pcep_versioning
*versioning
)
97 if (message
== NULL
) {
101 if (message
->msg_header
== NULL
) {
105 /* Internal buffer used for the entire message. Later, once the entire
106 * length is known, memory will be allocated and this buffer will be
108 uint8_t message_buffer
[PCEP_MESSAGE_LENGTH
] = {0};
110 /* Write the message header. The message header length will be
111 * written when the entire length is known. */
112 uint32_t message_length
= MESSAGE_HEADER_LENGTH
;
113 uint16_t net_order_length
= 0;
114 message_buffer
[0] = (message
->msg_header
->pcep_version
<< 5) & 0xf0;
115 message_buffer
[1] = message
->msg_header
->type
;
117 if (message
->obj_list
== NULL
) {
118 net_order_length
= htons(message_length
);
119 memcpy(message_buffer
+ 2, &net_order_length
,
120 sizeof(net_order_length
));
121 message
->encoded_message
=
122 pceplib_malloc(PCEPLIB_MESSAGES
, message_length
);
123 memcpy(message
->encoded_message
, message_buffer
,
125 message
->encoded_message_length
= message_length
;
130 /* Encode each of the objects */
131 double_linked_list_node
*node
= message
->obj_list
->head
;
132 for (; node
!= NULL
; node
= node
->next_node
) {
134 pcep_encode_object(node
->data
, versioning
,
135 message_buffer
+ message_length
);
136 if (message_length
>= PCEP_MESSAGE_LENGTH
) {
137 message
->encoded_message
= NULL
;
138 message
->encoded_message_length
= 0;
143 net_order_length
= htons(message_length
);
144 memcpy(message_buffer
+ 2, &net_order_length
, sizeof(net_order_length
));
145 message
->encoded_message
=
146 pceplib_malloc(PCEPLIB_MESSAGES
, message_length
);
147 memcpy(message
->encoded_message
, message_buffer
, message_length
);
148 message
->encoded_message_length
= message_length
;
155 /* Expecting Host byte ordered header */
156 static bool validate_msg_header(uint8_t msg_version
, uint8_t msg_flags
,
157 uint8_t msg_type
, uint16_t msg_length
)
159 /* Invalid message if the length is less than the header
160 * size or if its not a multiple of 4 */
161 if (msg_length
< MESSAGE_HEADER_LENGTH
|| (msg_length
% 4) != 0) {
163 "%s: Invalid PCEP message header length [%d]",
164 __func__
, msg_length
);
168 if (msg_version
!= PCEP_MESSAGE_HEADER_VERSION
) {
171 "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]",
172 __func__
, msg_version
, PCEP_MESSAGE_HEADER_VERSION
);
176 if (msg_flags
!= 0) {
178 "%s: Invalid PCEP message header flags [0x%x]",
179 __func__
, msg_flags
);
184 /* Supported message types */
186 case PCEP_TYPE_KEEPALIVE
:
187 case PCEP_TYPE_PCREQ
:
188 case PCEP_TYPE_PCREP
:
189 case PCEP_TYPE_PCNOTF
:
190 case PCEP_TYPE_ERROR
:
191 case PCEP_TYPE_CLOSE
:
192 case PCEP_TYPE_REPORT
:
193 case PCEP_TYPE_UPDATE
:
194 case PCEP_TYPE_INITIATE
:
197 pcep_log(LOG_INFO
, "%s: Invalid PCEP message header type [%d]",
206 /* Internal util function */
207 static uint16_t pcep_decode_msg_header(const uint8_t *msg_buf
,
208 uint8_t *msg_version
, uint8_t *msg_flags
,
211 // Check RFC 5440 for version and flags position.
212 // 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
213 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
214 //| Ver | Flags | Message-Type | Message-Length |
215 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
216 *msg_version
= (msg_buf
[0] >> 5) & 0x07;
217 *msg_flags
= (msg_buf
[0] & 0x1f);
218 *msg_type
= msg_buf
[1];
219 uint16_t host_order_length
;
220 memcpy(&host_order_length
, msg_buf
+ 2, sizeof(host_order_length
));
221 return ntohs(host_order_length
);
224 /* Decode the message header and return the message length */
225 int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf
)
232 msg_length
= pcep_decode_msg_header(msg_buf
, &msg_version
, &msg_flags
,
235 return ((validate_msg_header(msg_version
, msg_flags
, msg_type
,
239 : (int32_t)msg_length
);
242 bool validate_message_objects(struct pcep_message
*msg
)
244 if (msg
->msg_header
->type
>= PCEP_TYPE_START_TLS
) {
247 "%s: Rejecting received message: Unknown message type [%d]",
248 __func__
, msg
->msg_header
->type
);
252 const enum pcep_object_classes
*object_classes
=
253 MANDATORY_MESSAGE_OBJECT_CLASSES
[msg
->msg_header
->type
];
254 double_linked_list_node
*node
;
256 for (node
= (msg
->obj_list
== NULL
? NULL
: msg
->obj_list
->head
),
258 index
< NUM_CHECKED_OBJECTS
;
259 index
++, (node
= (node
== NULL
? NULL
: node
->next_node
))) {
260 struct pcep_object_header
*obj
=
263 : (struct pcep_object_header
*)node
->data
);
265 if ((int)object_classes
[index
] == NO_OBJECT
) {
269 "%s: Rejecting received message: Unexpected object [%d] present",
270 __func__
, obj
->object_class
);
273 } else if (object_classes
[index
] != ANY_OBJECT
) {
277 "%s: Rejecting received message: Expecting object in position [%d], but none received",
280 } else if (object_classes
[index
] != obj
->object_class
) {
283 "%s: Rejecting received message: Unexpected Object Class received [%d]",
284 __func__
, object_classes
[index
]);
293 struct pcep_message
*pcep_decode_message(const uint8_t *msg_buf
)
300 msg_length
= pcep_decode_msg_header(msg_buf
, &msg_version
, &msg_flags
,
302 if (msg_length
== 0) {
303 pcep_log(LOG_INFO
, "%s: Discarding empty message", __func__
);
306 if (msg_length
>= PCEP_MESSAGE_LENGTH
) {
307 pcep_log(LOG_INFO
, "%s: Discarding message too big", __func__
);
311 struct pcep_message
*msg
=
312 pceplib_calloc(PCEPLIB_MESSAGES
, sizeof(struct pcep_message
));
314 msg
->msg_header
= pceplib_malloc(PCEPLIB_MESSAGES
,
315 sizeof(struct pcep_message_header
));
316 msg
->msg_header
->pcep_version
= msg_version
;
317 msg
->msg_header
->type
= msg_type
;
319 msg
->obj_list
= dll_initialize();
320 msg
->encoded_message
= pceplib_malloc(PCEPLIB_MESSAGES
, msg_length
);
321 memcpy(msg
->encoded_message
, msg_buf
, msg_length
);
322 msg
->encoded_message_length
= msg_length
;
324 uint16_t bytes_read
= MESSAGE_HEADER_LENGTH
;
325 while ((msg_length
- bytes_read
) >= OBJECT_HEADER_LENGTH
) {
326 struct pcep_object_header
*obj_hdr
=
327 pcep_decode_object(msg_buf
+ bytes_read
);
329 if (obj_hdr
== NULL
) {
330 pcep_log(LOG_INFO
, "%s: Discarding invalid message",
332 pcep_msg_free_message(msg
);
337 dll_append(msg
->obj_list
, obj_hdr
);
338 bytes_read
+= obj_hdr
->encoded_object_length
;
341 if (validate_message_objects(msg
) == false) {
342 pcep_log(LOG_INFO
, "%s: Discarding invalid message", __func__
);
343 pcep_msg_free_message(msg
);
351 struct pcep_versioning
*create_default_pcep_versioning()
353 struct pcep_versioning
*versioning
=
354 pceplib_malloc(PCEPLIB_INFRA
, sizeof(struct pcep_versioning
));
355 memset(versioning
, 0, sizeof(struct pcep_versioning
));
360 void destroy_pcep_versioning(struct pcep_versioning
*versioning
)
362 pceplib_free(PCEPLIB_INFRA
, versioning
);