]> git.proxmox.com Git - mirror_frr.git/blob - pceplib/pcep_msg_messages_encoding.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / pceplib / pcep_msg_messages_encoding.c
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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35
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"
42
43 #define ANY_OBJECT 0
44 #define NO_OBJECT -1
45 #define NUM_CHECKED_OBJECTS 4
46 /* It wont compile with this definition:
47 static const int
48 MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS]
49 */
50 static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES[13][4] =
51 {
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 */
78 };
79
80 /* PCEP Message Common Header, According to RFC 5440
81 *
82 * 0 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 *
88 * Ver (Version - 3 bits): PCEP version number. Current version is version 1.
89 *
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.
93 */
94 void pcep_encode_message(struct pcep_message *message,
95 struct pcep_versioning *versioning)
96 {
97 if (message == NULL) {
98 return;
99 }
100
101 if (message->msg_header == NULL) {
102 return;
103 }
104
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
107 * copied. */
108 uint8_t message_buffer[PCEP_MESSAGE_LENGTH] = {0};
109
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;
116
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,
124 message_length);
125 message->encoded_message_length = message_length;
126
127 return;
128 }
129
130 /* Encode each of the objects */
131 double_linked_list_node *node = message->obj_list->head;
132 for (; node != NULL; node = node->next_node) {
133 message_length +=
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;
139 return;
140 }
141 }
142
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;
149 }
150
151 /*
152 * Decoding functions
153 */
154
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)
158 {
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) {
162 pcep_log(LOG_INFO,
163 "%s: Invalid PCEP message header length [%d]",
164 __func__, msg_length);
165 return false;
166 }
167
168 if (msg_version != PCEP_MESSAGE_HEADER_VERSION) {
169 pcep_log(
170 LOG_INFO,
171 "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]",
172 __func__, msg_version, PCEP_MESSAGE_HEADER_VERSION);
173 return false;
174 }
175
176 if (msg_flags != 0) {
177 pcep_log(LOG_INFO,
178 "%s: Invalid PCEP message header flags [0x%x]",
179 __func__, msg_flags);
180 return false;
181 }
182
183 switch (msg_type) {
184 /* Supported message types */
185 case PCEP_TYPE_OPEN:
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:
195 break;
196 default:
197 pcep_log(LOG_INFO, "%s: Invalid PCEP message header type [%d]",
198 __func__, msg_type);
199 return false;
200 break;
201 }
202
203 return true;
204 }
205
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,
209 uint8_t *msg_type)
210 {
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);
222 }
223
224 /* Decode the message header and return the message length */
225 int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf)
226 {
227 uint8_t msg_version;
228 uint8_t msg_flags;
229 uint8_t msg_type;
230 uint32_t msg_length;
231
232 msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
233 &msg_type);
234
235 return ((validate_msg_header(msg_version, msg_flags, msg_type,
236 msg_length)
237 == false)
238 ? -1
239 : (int32_t)msg_length);
240 }
241
242 bool validate_message_objects(struct pcep_message *msg)
243 {
244 if (msg->msg_header->type >= PCEP_TYPE_START_TLS) {
245 pcep_log(
246 LOG_INFO,
247 "%s: Rejecting received message: Unknown message type [%d]",
248 __func__, msg->msg_header->type);
249 return false;
250 }
251
252 const enum pcep_object_classes *object_classes =
253 MANDATORY_MESSAGE_OBJECT_CLASSES[msg->msg_header->type];
254 double_linked_list_node *node;
255 int index;
256 for (node = (msg->obj_list == NULL ? NULL : msg->obj_list->head),
257 index = 0;
258 index < NUM_CHECKED_OBJECTS;
259 index++, (node = (node == NULL ? NULL : node->next_node))) {
260 struct pcep_object_header *obj =
261 ((node == NULL)
262 ? NULL
263 : (struct pcep_object_header *)node->data);
264
265 if ((int)object_classes[index] == NO_OBJECT) {
266 if (node != NULL) {
267 pcep_log(
268 LOG_INFO,
269 "%s: Rejecting received message: Unexpected object [%d] present",
270 __func__, obj->object_class);
271 return false;
272 }
273 } else if (object_classes[index] != ANY_OBJECT) {
274 if (node == NULL) {
275 pcep_log(
276 LOG_INFO,
277 "%s: Rejecting received message: Expecting object in position [%d], but none received",
278 __func__, index);
279 return false;
280 } else if (object_classes[index] != obj->object_class) {
281 pcep_log(
282 LOG_INFO,
283 "%s: Rejecting received message: Unexpected Object Class received [%d]",
284 __func__, object_classes[index]);
285 return false;
286 }
287 }
288 }
289
290 return true;
291 }
292
293 struct pcep_message *pcep_decode_message(const uint8_t *msg_buf)
294 {
295 uint8_t msg_version;
296 uint8_t msg_flags;
297 uint8_t msg_type;
298 uint16_t msg_length;
299
300 msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
301 &msg_type);
302 if (msg_length == 0) {
303 pcep_log(LOG_INFO, "%s: Discarding empty message", __func__);
304 return NULL;
305 }
306 if (msg_length >= PCEP_MESSAGE_LENGTH) {
307 pcep_log(LOG_INFO, "%s: Discarding message too big", __func__);
308 return NULL;
309 }
310
311 struct pcep_message *msg =
312 pceplib_calloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
313
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;
318
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;
323
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);
328
329 if (obj_hdr == NULL) {
330 pcep_log(LOG_INFO, "%s: Discarding invalid message",
331 __func__);
332 pcep_msg_free_message(msg);
333
334 return NULL;
335 }
336
337 dll_append(msg->obj_list, obj_hdr);
338 bytes_read += obj_hdr->encoded_object_length;
339 }
340
341 if (validate_message_objects(msg) == false) {
342 pcep_log(LOG_INFO, "%s: Discarding invalid message", __func__);
343 pcep_msg_free_message(msg);
344
345 return NULL;
346 }
347
348 return msg;
349 }
350
351 struct pcep_versioning *create_default_pcep_versioning(void)
352 {
353 struct pcep_versioning *versioning =
354 pceplib_malloc(PCEPLIB_INFRA, sizeof(struct pcep_versioning));
355 memset(versioning, 0, sizeof(struct pcep_versioning));
356
357 return versioning;
358 }
359
360 void destroy_pcep_versioning(struct pcep_versioning *versioning)
361 {
362 pceplib_free(PCEPLIB_INFRA, versioning);
363 }