]> git.proxmox.com Git - mirror_frr.git/blame - pceplib/pcep_msg_messages_encoding.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / pceplib / pcep_msg_messages_encoding.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: LGPL-2.1-or-later
74971473
JG
2/*
3 * This file is part of the PCEPlib, a PCEP protocol library.
4 *
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
6 *
74971473
JG
7 * Author : Brady Johnson <brady@voltanet.io>
8 *
9 */
10
11
12/*
13 * Encoding and decoding for PCEP messages.
14 */
15
1f8031f7
DL
16#ifdef HAVE_CONFIG_H
17#include "config.h"
18#endif
19
74971473
JG
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23
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"
30
31#define ANY_OBJECT 0
32#define NO_OBJECT -1
33#define NUM_CHECKED_OBJECTS 4
34/* It wont compile with this definition:
35 static const int
36 MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS]
37 */
38static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES[13][4] =
39 {
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 */
66};
67
68/* PCEP Message Common Header, According to RFC 5440
69 *
70 * 0 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75 *
76 * Ver (Version - 3 bits): PCEP version number. Current version is version 1.
77 *
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.
81 */
82void pcep_encode_message(struct pcep_message *message,
83 struct pcep_versioning *versioning)
84{
85 if (message == NULL) {
86 return;
87 }
88
89 if (message->msg_header == NULL) {
90 return;
91 }
92
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
95 * copied. */
96 uint8_t message_buffer[PCEP_MESSAGE_LENGTH] = {0};
97
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;
104
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,
112 message_length);
113 message->encoded_message_length = message_length;
114
115 return;
116 }
117
118 /* Encode each of the objects */
119 double_linked_list_node *node = message->obj_list->head;
120 for (; node != NULL; node = node->next_node) {
121 message_length +=
122 pcep_encode_object(node->data, versioning,
123 message_buffer + message_length);
7ed8c4b1 124 if (message_length >= PCEP_MESSAGE_LENGTH) {
74971473
JG
125 message->encoded_message = NULL;
126 message->encoded_message_length = 0;
127 return;
128 }
129 }
130
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;
137}
138
139/*
140 * Decoding functions
141 */
142
143/* Expecting Host byte ordered header */
144static bool validate_msg_header(uint8_t msg_version, uint8_t msg_flags,
145 uint8_t msg_type, uint16_t msg_length)
146{
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) {
150 pcep_log(LOG_INFO,
151 "%s: Invalid PCEP message header length [%d]",
152 __func__, msg_length);
153 return false;
154 }
155
156 if (msg_version != PCEP_MESSAGE_HEADER_VERSION) {
157 pcep_log(
158 LOG_INFO,
159 "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]",
160 __func__, msg_version, PCEP_MESSAGE_HEADER_VERSION);
161 return false;
162 }
163
164 if (msg_flags != 0) {
165 pcep_log(LOG_INFO,
166 "%s: Invalid PCEP message header flags [0x%x]",
167 __func__, msg_flags);
168 return false;
169 }
170
171 switch (msg_type) {
172 /* Supported message types */
173 case PCEP_TYPE_OPEN:
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:
183 break;
184 default:
185 pcep_log(LOG_INFO, "%s: Invalid PCEP message header type [%d]",
186 __func__, msg_type);
187 return false;
188 break;
189 }
190
191 return true;
192}
193
194/* Internal util function */
195static uint16_t pcep_decode_msg_header(const uint8_t *msg_buf,
196 uint8_t *msg_version, uint8_t *msg_flags,
197 uint8_t *msg_type)
198{
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);
210}
211
212/* Decode the message header and return the message length */
213int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf)
214{
215 uint8_t msg_version;
216 uint8_t msg_flags;
217 uint8_t msg_type;
218 uint32_t msg_length;
219
220 msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
221 &msg_type);
222
223 return ((validate_msg_header(msg_version, msg_flags, msg_type,
224 msg_length)
225 == false)
226 ? -1
227 : (int32_t)msg_length);
228}
229
230bool validate_message_objects(struct pcep_message *msg)
231{
232 if (msg->msg_header->type >= PCEP_TYPE_START_TLS) {
233 pcep_log(
234 LOG_INFO,
235 "%s: Rejecting received message: Unknown message type [%d]",
236 __func__, msg->msg_header->type);
237 return false;
238 }
239
240 const enum pcep_object_classes *object_classes =
241 MANDATORY_MESSAGE_OBJECT_CLASSES[msg->msg_header->type];
242 double_linked_list_node *node;
243 int index;
244 for (node = (msg->obj_list == NULL ? NULL : msg->obj_list->head),
245 index = 0;
246 index < NUM_CHECKED_OBJECTS;
247 index++, (node = (node == NULL ? NULL : node->next_node))) {
248 struct pcep_object_header *obj =
249 ((node == NULL)
250 ? NULL
251 : (struct pcep_object_header *)node->data);
252
253 if ((int)object_classes[index] == NO_OBJECT) {
254 if (node != NULL) {
255 pcep_log(
256 LOG_INFO,
257 "%s: Rejecting received message: Unexpected object [%d] present",
258 __func__, obj->object_class);
259 return false;
260 }
261 } else if (object_classes[index] != ANY_OBJECT) {
262 if (node == NULL) {
263 pcep_log(
264 LOG_INFO,
265 "%s: Rejecting received message: Expecting object in position [%d], but none received",
266 __func__, index);
267 return false;
268 } else if (object_classes[index] != obj->object_class) {
269 pcep_log(
270 LOG_INFO,
271 "%s: Rejecting received message: Unexpected Object Class received [%d]",
272 __func__, object_classes[index]);
273 return false;
274 }
275 }
276 }
277
278 return true;
279}
280
281struct pcep_message *pcep_decode_message(const uint8_t *msg_buf)
282{
283 uint8_t msg_version;
284 uint8_t msg_flags;
285 uint8_t msg_type;
286 uint16_t msg_length;
287
288 msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
289 &msg_type);
7ed8c4b1
JG
290 if (msg_length == 0) {
291 pcep_log(LOG_INFO, "%s: Discarding empty message", __func__);
292 return NULL;
293 }
294 if (msg_length >= PCEP_MESSAGE_LENGTH) {
295 pcep_log(LOG_INFO, "%s: Discarding message too big", __func__);
296 return NULL;
297 }
74971473
JG
298
299 struct pcep_message *msg =
300 pceplib_calloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
301
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;
306
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;
311
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);
316
317 if (obj_hdr == NULL) {
318 pcep_log(LOG_INFO, "%s: Discarding invalid message",
319 __func__);
320 pcep_msg_free_message(msg);
321
322 return NULL;
323 }
324
325 dll_append(msg->obj_list, obj_hdr);
326 bytes_read += obj_hdr->encoded_object_length;
327 }
328
329 if (validate_message_objects(msg) == false) {
330 pcep_log(LOG_INFO, "%s: Discarding invalid message", __func__);
331 pcep_msg_free_message(msg);
332
333 return NULL;
334 }
335
336 return msg;
337}
338
2816045a 339struct pcep_versioning *create_default_pcep_versioning(void)
74971473
JG
340{
341 struct pcep_versioning *versioning =
342 pceplib_malloc(PCEPLIB_INFRA, sizeof(struct pcep_versioning));
343 memset(versioning, 0, sizeof(struct pcep_versioning));
344
345 return versioning;
346}
347
348void destroy_pcep_versioning(struct pcep_versioning *versioning)
349{
350 pceplib_free(PCEPLIB_INFRA, versioning);
351}