]> git.proxmox.com Git - mirror_frr.git/blame - pceplib/pcep_msg_messages_encoding.c
pceplib: Integrate pcelib into frr
[mirror_frr.git] / pceplib / pcep_msg_messages_encoding.c
CommitLineData
74971473
JG
1/*
2 * This file is part of the PCEPlib, a PCEP protocol library.
3 *
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * Author : Brady Johnson <brady@voltanet.io>
20 *
21 */
22
23
24/*
25 * Encoding and decoding for PCEP messages.
26 */
27
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31
32#include "pcep_msg_encoding.h"
33#include "pcep_msg_messages.h"
34#include "pcep_msg_objects.h"
35#include "pcep_msg_tools.h"
36#include "pcep_utils_logging.h"
37#include "pcep_utils_memory.h"
38
39#define ANY_OBJECT 0
40#define NO_OBJECT -1
41#define NUM_CHECKED_OBJECTS 4
42/* It wont compile with this definition:
43 static const int
44 MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS]
45 */
46static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES[13][4] =
47 {
48 {NO_OBJECT, NO_OBJECT, NO_OBJECT,
49 NO_OBJECT}, /* unsupported message ID = 0 */
50 {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT,
51 NO_OBJECT}, /* PCEP_TYPE_OPEN = 1 */
52 {NO_OBJECT, NO_OBJECT, NO_OBJECT,
53 NO_OBJECT}, /* PCEP_TYPE_KEEPALIVE = 2 */
54 {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT,
55 ANY_OBJECT}, /* PCEP_TYPE_PCREQ = 3 */
56 {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT,
57 ANY_OBJECT}, /* PCEP_TYPE_PCREP = 4 */
58 {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT,
59 ANY_OBJECT}, /* PCEP_TYPE_PCNOTF = 5 */
60 {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT,
61 ANY_OBJECT}, /* PCEP_TYPE_ERROR = 6 */
62 {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT,
63 NO_OBJECT}, /* PCEP_TYPE_CLOSE = 7 */
64 {NO_OBJECT, NO_OBJECT, NO_OBJECT,
65 NO_OBJECT}, /* unsupported message ID = 8 */
66 {NO_OBJECT, NO_OBJECT, NO_OBJECT,
67 NO_OBJECT}, /* unsupported message ID = 9 */
68 {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
69 ANY_OBJECT}, /* PCEP_TYPE_REPORT = 10 */
70 {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
71 ANY_OBJECT}, /* PCEP_TYPE_UPDATE = 11 */
72 {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
73 ANY_OBJECT}, /* PCEP_TYPE_INITIATE = 12 */
74};
75
76/* PCEP Message Common Header, According to RFC 5440
77 *
78 * 0 1 2 3
79 * 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
80 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81 * | Ver | Flags | Message-Type | Message-Length |
82 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83 *
84 * Ver (Version - 3 bits): PCEP version number. Current version is version 1.
85 *
86 * Flags (5 bits): No flags are currently defined. Unassigned bits are
87 * considered as reserved. They MUST be set to zero on transmission
88 * and MUST be ignored on receipt.
89 */
90void pcep_encode_message(struct pcep_message *message,
91 struct pcep_versioning *versioning)
92{
93 if (message == NULL) {
94 return;
95 }
96
97 if (message->msg_header == NULL) {
98 return;
99 }
100
101 /* Internal buffer used for the entire message. Later, once the entire
102 * length is known, memory will be allocated and this buffer will be
103 * copied. */
104 uint8_t message_buffer[PCEP_MESSAGE_LENGTH] = {0};
105
106 /* Write the message header. The message header length will be
107 * written when the entire length is known. */
108 uint32_t message_length = MESSAGE_HEADER_LENGTH;
109 uint16_t net_order_length = 0;
110 message_buffer[0] = (message->msg_header->pcep_version << 5) & 0xf0;
111 message_buffer[1] = message->msg_header->type;
112
113 if (message->obj_list == NULL) {
114 net_order_length = htons(message_length);
115 memcpy(message_buffer + 2, &net_order_length,
116 sizeof(net_order_length));
117 message->encoded_message =
118 pceplib_malloc(PCEPLIB_MESSAGES, message_length);
119 memcpy(message->encoded_message, message_buffer,
120 message_length);
121 message->encoded_message_length = message_length;
122
123 return;
124 }
125
126 /* Encode each of the objects */
127 double_linked_list_node *node = message->obj_list->head;
128 for (; node != NULL; node = node->next_node) {
129 message_length +=
130 pcep_encode_object(node->data, versioning,
131 message_buffer + message_length);
132 if (message_length > PCEP_MESSAGE_LENGTH) {
133 message->encoded_message = NULL;
134 message->encoded_message_length = 0;
135 return;
136 }
137 }
138
139 net_order_length = htons(message_length);
140 memcpy(message_buffer + 2, &net_order_length, sizeof(net_order_length));
141 message->encoded_message =
142 pceplib_malloc(PCEPLIB_MESSAGES, message_length);
143 memcpy(message->encoded_message, message_buffer, message_length);
144 message->encoded_message_length = message_length;
145}
146
147/*
148 * Decoding functions
149 */
150
151/* Expecting Host byte ordered header */
152static bool validate_msg_header(uint8_t msg_version, uint8_t msg_flags,
153 uint8_t msg_type, uint16_t msg_length)
154{
155 /* Invalid message if the length is less than the header
156 * size or if its not a multiple of 4 */
157 if (msg_length < MESSAGE_HEADER_LENGTH || (msg_length % 4) != 0) {
158 pcep_log(LOG_INFO,
159 "%s: Invalid PCEP message header length [%d]",
160 __func__, msg_length);
161 return false;
162 }
163
164 if (msg_version != PCEP_MESSAGE_HEADER_VERSION) {
165 pcep_log(
166 LOG_INFO,
167 "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]",
168 __func__, msg_version, PCEP_MESSAGE_HEADER_VERSION);
169 return false;
170 }
171
172 if (msg_flags != 0) {
173 pcep_log(LOG_INFO,
174 "%s: Invalid PCEP message header flags [0x%x]",
175 __func__, msg_flags);
176 return false;
177 }
178
179 switch (msg_type) {
180 /* Supported message types */
181 case PCEP_TYPE_OPEN:
182 case PCEP_TYPE_KEEPALIVE:
183 case PCEP_TYPE_PCREQ:
184 case PCEP_TYPE_PCREP:
185 case PCEP_TYPE_PCNOTF:
186 case PCEP_TYPE_ERROR:
187 case PCEP_TYPE_CLOSE:
188 case PCEP_TYPE_REPORT:
189 case PCEP_TYPE_UPDATE:
190 case PCEP_TYPE_INITIATE:
191 break;
192 default:
193 pcep_log(LOG_INFO, "%s: Invalid PCEP message header type [%d]",
194 __func__, msg_type);
195 return false;
196 break;
197 }
198
199 return true;
200}
201
202/* Internal util function */
203static uint16_t pcep_decode_msg_header(const uint8_t *msg_buf,
204 uint8_t *msg_version, uint8_t *msg_flags,
205 uint8_t *msg_type)
206{
207 // Check RFC 5440 for version and flags position.
208 // 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
209 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210 //| Ver | Flags | Message-Type | Message-Length |
211 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212 *msg_version = (msg_buf[0] >> 5) & 0x07;
213 *msg_flags = (msg_buf[0] & 0x1f);
214 *msg_type = msg_buf[1];
215 uint16_t host_order_length;
216 memcpy(&host_order_length, msg_buf + 2, sizeof(host_order_length));
217 return ntohs(host_order_length);
218}
219
220/* Decode the message header and return the message length */
221int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf)
222{
223 uint8_t msg_version;
224 uint8_t msg_flags;
225 uint8_t msg_type;
226 uint32_t msg_length;
227
228 msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
229 &msg_type);
230
231 return ((validate_msg_header(msg_version, msg_flags, msg_type,
232 msg_length)
233 == false)
234 ? -1
235 : (int32_t)msg_length);
236}
237
238bool validate_message_objects(struct pcep_message *msg)
239{
240 if (msg->msg_header->type >= PCEP_TYPE_START_TLS) {
241 pcep_log(
242 LOG_INFO,
243 "%s: Rejecting received message: Unknown message type [%d]",
244 __func__, msg->msg_header->type);
245 return false;
246 }
247
248 const enum pcep_object_classes *object_classes =
249 MANDATORY_MESSAGE_OBJECT_CLASSES[msg->msg_header->type];
250 double_linked_list_node *node;
251 int index;
252 for (node = (msg->obj_list == NULL ? NULL : msg->obj_list->head),
253 index = 0;
254 index < NUM_CHECKED_OBJECTS;
255 index++, (node = (node == NULL ? NULL : node->next_node))) {
256 struct pcep_object_header *obj =
257 ((node == NULL)
258 ? NULL
259 : (struct pcep_object_header *)node->data);
260
261 if ((int)object_classes[index] == NO_OBJECT) {
262 if (node != NULL) {
263 pcep_log(
264 LOG_INFO,
265 "%s: Rejecting received message: Unexpected object [%d] present",
266 __func__, obj->object_class);
267 return false;
268 }
269 } else if (object_classes[index] != ANY_OBJECT) {
270 if (node == NULL) {
271 pcep_log(
272 LOG_INFO,
273 "%s: Rejecting received message: Expecting object in position [%d], but none received",
274 __func__, index);
275 return false;
276 } else if (object_classes[index] != obj->object_class) {
277 pcep_log(
278 LOG_INFO,
279 "%s: Rejecting received message: Unexpected Object Class received [%d]",
280 __func__, object_classes[index]);
281 return false;
282 }
283 }
284 }
285
286 return true;
287}
288
289struct pcep_message *pcep_decode_message(const uint8_t *msg_buf)
290{
291 uint8_t msg_version;
292 uint8_t msg_flags;
293 uint8_t msg_type;
294 uint16_t msg_length;
295
296 msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
297 &msg_type);
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
339struct pcep_versioning *create_default_pcep_versioning()
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}