xref: /rk3399_ARM-atf/include/drivers/arm/sfcp.h (revision a8dc2595ab7e10dac8285d2c0b6da7ebbcd0edb0)
1 /*
2  * Copyright (c) 2026, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #ifndef __SFCP_H__
9 #define __SFCP_H__
10 
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 
15 #include <drivers/arm/sfcp_link_defs.h>
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 /**
22  * \brief Minimum buffer size (in bytes) required for any SFCP packet.
23  *
24  * \details
25  * This constant defines the smallest valid buffer size that can be passed to
26  * SFCP send/receive/init functions. It accounts for the packet header,
27  * required metadata fields, and any alignment requirements, but does not
28  * include any additional payload space.
29  *
30  * Buffers smaller than this size are guaranteed to be rejected with
31  * ::SFCP_ERROR_BUFFER_TOO_SMALL.
32  *
33  * This macro is intended for compile-time allocation checks or for ensuring
34  * that dynamically allocated buffers meet the protocol's minimum size
35  * requirements before calling SFCP APIs.
36  */
37 #define SFCP_BUFFER_MINIMUM_SIZE (40)
38 
39 /**
40  * \brief Library return codes for the SFCP API.
41  *
42  * Notes:
43  * - Polling receives SHOULD use the *_NO_MSG_AVAILABLE / *_NO_REPLY_AVAILABLE codes
44  *   when nothing is ready to read (non-fatal “no data” condition).
45  * - If a provided buffer is too small to hold the packet header + metadata,
46  *   the call MUST return SFCP_ERROR_BUFFER_TOO_SMALL.
47  */
48 enum sfcp_error_t {
49 	SFCP_ERROR_SUCCESS = 0,
50 	SFCP_ERROR_INVALID_POINTER,
51 	SFCP_ERROR_INVALID_SENDER_ID,
52 	SFCP_ERROR_INVALID_PACKET,
53 	SFCP_ERROR_MESSAGE_TOO_SMALL,
54 	SFCP_ERROR_BUFFER_TOO_SMALL,
55 	SFCP_ERROR_INVALID_LEGACY_FORMAT_CONFIGURATION,
56 	SFCP_ERROR_PAYLOAD_TOO_LARGE,
57 	SFCP_ERROR_CRYPTOGRAPHY_NOT_SUPPORTED,
58 	SFCP_ERROR_TRUSTED_SUBNET_MUST_BE_MANUALLY_SELECTED,
59 	SFCP_ERROR_PAYLOAD_INVALID_ALIGNMENT,
60 	SFCP_ERROR_ENCRYPTION_FAILED,
61 	SFCP_ERROR_DECRYPTION_FAILED,
62 	SFCP_ERROR_GENERATE_IV_FAILED,
63 	SFCP_ERROR_GENERATE_SESSION_KEY_SEED_FAILED,
64 	SFCP_ERROR_INVALID_TRUSTED_SUBNET_ID,
65 	SFCP_ERROR_TRUSTED_SUBNET_ALREADY_REGISTERED,
66 	SFCP_ERROR_INVALID_TRUSTED_SUBNET_NODE_ID,
67 	SFCP_ERROR_INVALID_TRUSTED_SUBNET_NODE_AMOUNT,
68 	SFCP_ERROR_INVALID_REPLY,
69 	SFCP_ERROR_INVALID_MSG,
70 	SFCP_ERROR_INVALID_NODE,
71 	SFCP_ERROR_NO_MSG_AVAILABLE,
72 	SFCP_ERROR_NO_REPLY_AVAILABLE,
73 	SFCP_ERROR_SEND_MSG_AGAIN,
74 	SFCP_ERROR_SEND_MSG_BUS_BUSY,
75 	SFCP_ERROR_INVALID_PROTOCOL_VERSION,
76 	SFCP_ERROR_INVALID_APPLICATION_ID,
77 	SFCP_ERROR_INVALID_CLIENT_ID,
78 	SFCP_ERROR_INVALID_CRYPTO_MODE,
79 	SFCP_ERROR_INVALID_MSG_TYPE,
80 	SFCP_ERROR_INVALID_SEQUENCE_NUMBER,
81 	SFCP_ERROR_INVALID_PACKET_SIZE,
82 	SFCP_ERROR_HANDLER_TABLE_FULL,
83 	SFCP_ERROR_INVALID_BUFFER_HANDLE,
84 	SFCP_ERROR_INVALID_TRUSTED_SUBNET_STATE,
85 	SFCP_ERROR_INTERNAL_HANDSHAKE_FAILURE,
86 	SFCP_ERROR_HANDSHAKE_GENERATE_RANDOM_FAILURE,
87 	SFCP_ERROR_HANDSHAKE_HASH_FAILURE,
88 	SFCP_ERROR_HANDSHAKE_HASH_ALG_UNSUPPORTED,
89 	SFCP_ERROR_HANDSHAKE_SETUP_SESSION_KEY_FAILURE,
90 	SFCP_ERROR_HANDSHAKE_REKEY_SESSION_KEY_FAILURE,
91 	SFCP_ERROR_HANDSHAKE_INVALIDATE_SESSION_KEY_FAILURE,
92 	SFCP_ERROR_HANDSHAKE_INVALID_RECEIVED_IV,
93 	SFCP_ERROR_HANDSHAKE_INVALID_RE_KEY_MSG,
94 	SFCP_ERROR_HANDSHAKE_INVALID_MUTUAL_AUTH_MSG,
95 	SFCP_ERROR_ALLOCATE_BUFFER_TOO_LARGE,
96 	SFCP_ERROR_ALLOCATE_BUFFER_FAILED,
97 	SFCP_ERROR_POP_BUFFER_FAILED,
98 	SFCP_ERROR_MSG_ALREADY_RECEIVED,
99 	SFCP_ERROR_MSG_OUT_OF_ORDER_TEMPORARY_FAILURE,
100 	SFCP_ERROR_PROTOCOL_ERROR,
101 	SFCP_ERROR_SEND_PACKET_BUS_BUSY,
102 	SFCP_ERROR_HAL_ERROR_BASE,
103 	SFCP_ERROR_HAL_ERROR_MAX = SFCP_ERROR_HAL_ERROR_BASE + 0x100,
104 	SFCP_ERROR_FORCE_UINT32T_MAX = UINT32_MAX,
105 };
106 
107 struct sfcp_packet_t;
108 
109 /**
110  * \brief Metadata captured at send time to match a future reply.
111  *
112  * \details
113  * The sender MUST NOT reuse a sequence number until the reply for the message
114  * using that sequence number has been received. If the ID extension is used, the
115  * (message_id, client_id) pair MUST remain unique among in-flight messages.
116  * If a timeout-retry mechanism is used, the sender MUST increment sequence numbers
117  * between messages and keep metadata for all outstanding messages to handle delayed
118  * replies.
119  */
120 struct sfcp_reply_metadata_t {
121 	sfcp_node_id_t receiver; /**< Intended receiver node ID. */
122 	bool uses_cryptography; /**< Whether crypto/auth is used for this exchange.
123                                          Replies MUST mirror this bit (except error replies,
124                                          which are never encrypted). */
125 	uint16_t client_id; /**< Client ID (0 if ID extension not used). */
126 	uint16_t application_id; /**< Application ID (0 if ID extension not used). */
127 	uint8_t message_id; /**< Message ID for matching. */
128 	uint8_t trusted_subnet_id; /**< Trusted subnet ID (only if uses_cryptography). */
129 };
130 
131 /**
132  * \brief Metadata captured at receive time to initialize a reply.
133  *
134  * \details
135  * A reply MUST use the same client ID and application ID as the original message,
136  * so it routes back to the correct caller/handler.
137  * The reply MUST also mirror the message’s uses_cryptography bit (except
138  * for protocol error replies, which cannot be encrypted).
139  */
140 struct sfcp_msg_metadata_t {
141 	sfcp_node_id_t
142 		sender; /**< Original sender node ID (now the reply receiver). */
143 	bool uses_cryptography; /**< Whether the original message used crypto/auth. */
144 	uint16_t client_id; /**< Client ID from the original message (or 0). */
145 	uint16_t application_id; /**< Application ID from the original message (or 0). */
146 	uint8_t message_id; /**< Message ID from the original message. */
147 	uint8_t trusted_subnet_id; /**< Trusted subnet ID from the original message. */
148 };
149 
150 /**
151  * \brief Opaque handle for an entry in the internal message/reply buffer.
152  *
153  * \details
154  * A value of this type is passed to handler callbacks and later used with the
155  * *_pop_* functions to retrieve the corresponding packet from the internal
156  * buffer. The concrete encoding is implementation-defined.
157  */
158 typedef uint32_t sfcp_buffer_handle_t;
159 
160 /**
161  * \brief Prototype for asynchronous handler functions (message or reply).
162  *
163  * \details
164  * The handler is invoked from the IRQ/deferred context with a buffer handle.
165  * The handler typically enqueues the handle and returns quickly; later, the
166  * consumer calls the appropriate *_pop_* routine to copy data out.
167  *
168  * \param[in] buffer_handle  Handle for the buffered packet to process.
169  *
170  * \return SFCP_ERROR_SUCCESS if the handle was accepted/queued; an error
171  *         code otherwise.
172  */
173 typedef enum sfcp_error_t (*sfcp_handler_t)(sfcp_buffer_handle_t buffer_handle);
174 
175 /**
176  * \brief Initializes the RSE communications layer.
177  *
178  * \details
179  * Initializes the transport/link integration used by the SFCP library.
180  *
181  * \return SFCP_ERROR_SUCCESS on success; otherwise a translated HAL error.
182  */
183 enum sfcp_error_t sfcp_init(void);
184 
185 /**
186  * \brief Prepare a message packet and payload buffer for sending.
187  *
188  * \param[in]  buf               Caller-provided buffer that will hold the entire packet
189  *                               (header + optional ID/crypto metadata + payload).
190  * \param[in]  buf_size          Size of \p buf.
191  * \param[in]  receiver          Destination node ID.
192  * \param[in]  application_id    Application ID at the receiver (0 means the receiver node itself).
193  * \param[in]  client_id         Client ID on behalf of which the sender is acting (0 means the sender node).
194  * \param[in]  needs_reply       If true, the packet type is MSG_NEEDS_REPLY; otherwise MSG_NO_REPLY.
195  *                               For MSG_NO_REPLY, the receiver MUST NOT send any reply.
196  * \param[in]  manually_specify_ts_id If true, use the provided trusted_subnet_id; otherwise auto-select.
197  * \param[in]  trusted_subnet_id Trusted subnet ID to use (only if manually_specify_ts_id is true).
198  * \param[out] payload           Pointer within \p buf where the caller writes plaintext payload.
199  * \param[out] payload_len       Capacity of the payload area (bytes). Caller MUST NOT exceed this.
200  * \param[out] msg               Pointer to the prepared packet structure within \p buf.
201  * \param[out] msg_size          Total packet size (header + metadata + payload capacity) to pass to send.
202  * \param[out] metadata          Populated with values needed to match a future reply.
203  *
204  * \return SFCP_ERROR_SUCCESS on success;
205  *         SFCP_ERROR_CRYPTOGRAPHY_NOT_SUPPORTED if crypto is requested but unsupported;
206  *         SFCP_ERROR_INVALID_BUFFER / SFCP_ERROR_BUFFER_TOO_SMALL on buffer issues;
207  *         SFCP_ERROR_INVALID_NODE for invalid destination.
208  */
209 enum sfcp_error_t sfcp_init_msg(uint8_t *buf, size_t buf_size,
210 				sfcp_node_id_t receiver,
211 				uint16_t application_id, uint16_t client_id,
212 				bool needs_reply, bool manually_specify_ts_id,
213 				uint8_t trusted_subnet_id, uint8_t **payload,
214 				size_t *payload_len, struct sfcp_packet_t **msg,
215 				size_t *msg_size,
216 				struct sfcp_reply_metadata_t *metadata);
217 
218 /**
219  * \brief Transmit a prepared message packet.
220  *
221  * \param[in] msg           Pointer to packet prepared by sfcp_init_msg (unaltered).
222  * \param[in] msg_size      Total size of the packet buffer.
223  * \param[in] payload_size  Number of bytes of the payload area actually used.
224  *
225  * \return SFCP_ERROR_SUCCESS on success;
226  *         SFCP_ERROR_INVALID_PACKET / SFCP_ERROR_MESSAGE_TOO_SMALL /
227  *         SFCP_ERROR_PAYLOAD_TOO_LARGE if the packet is malformed or sizes mismatch;
228  *         SFCP_ERROR_INVALID_NODE if routing fails;
229  *         a translated HAL error on transport failure.
230  *
231  * \note The application supplies plaintext in the payload; the library performs any required
232  *       encryption/authentication transparently before sending.
233  */
234 enum sfcp_error_t sfcp_send_msg(struct sfcp_packet_t *msg, size_t msg_size,
235 				size_t payload_size);
236 
237 /**
238  * \brief Prepare a reply packet and payload buffer corresponding to a received message.
239  *
240  * \param[in]  buf               Caller-provided buffer for the entire reply packet.
241  * \param[in]  buf_size          Size of \p buf.
242  * \param[in]  metadata          Metadata captured when the message was received; the reply will:
243  *                               - mirror uses_cryptography (except protocol error replies,
244  *                                 which cannot be encrypted), and
245  *                               - use the same client_id, application_id, and message_id.
246  * \param[out] payload           Pointer within \p buf where the caller writes the plaintext reply payload.
247  * \param[out] payload_len       Capacity of the reply payload area (bytes).
248  * \param[out] reply             Pointer to the prepared reply packet within \p buf.
249  * \param[out] reply_size        Total packet size to pass to sfcp_send_reply.
250  *
251  * \return SFCP_ERROR_SUCCESS on success; *_BUFFER_TOO_SMALL if \p buf is insufficient; or a
252  *         translated HAL error if local node ID cannot be obtained.
253  */
254 enum sfcp_error_t sfcp_init_reply(uint8_t *buf, size_t buf_size,
255 				  struct sfcp_msg_metadata_t metadata,
256 				  uint8_t **payload, size_t *payload_len,
257 				  struct sfcp_packet_t **reply,
258 				  size_t *reply_size);
259 
260 /**
261  * \brief Transmit a prepared reply packet.
262  *
263  * \param[in] reply          Pointer to packet prepared by sfcp_init_reply (unaltered).
264  * \param[in] reply_size     Total size of the packet buffer.
265  * \param[in] payload_size   Number of bytes of the payload area actually used.
266  *
267  * \return SFCP_ERROR_SUCCESS on success; the same validation/routing/transport errors as send_msg.
268  *
269  * \note Normal replies MUST mirror the message’s uses_cryptography bit.
270  *       Protocol error replies are never encrypted.
271  */
272 enum sfcp_error_t sfcp_send_reply(struct sfcp_packet_t *reply,
273 				  size_t reply_size, size_t payload_size);
274 
275 /**
276  * \brief Receive a message (polling mode).
277  *
278  * \details
279  * Retrieves the next available message destined for \p sender (by route), validates it,
280  * and exposes the plaintext payload pointer and capacity. If nothing is available, returns
281  * SFCP_ERROR_NO_MSG_AVAILABLE (non-fatal).
282  *
283  * Validation rules enforced include:
284  * - Packet type MUST be MSG_NEEDS_REPLY or MSG_NO_REPLY.
285  * - Protocol version MUST equal 0b10.
286  * - If ID extension not present, receiver MUST treat client_id/application_id as 0;
287  *   otherwise, they MUST be read from their fields.
288  * - Receiver MUST route handling based on application_id; if out of range, return
289  *   INVALID_APPLICATION_ID (sender of MSG_NEEDS_REPLY will receive an error reply).
290  * - If message crypto setting doesn’t match the expected uses_cryptography, return INVALID_CRYPTO_MODE.
291  * - For MSG_NO_REPLY, the receiver MUST NOT send a reply even on failure.
292  *
293  * \param[in]  buf                Buffer to receive the packet.
294  * \param[in]  buf_size           Size of \p buf.
295  * \param[in]  any_sender         Message can come from any known sender, if set \p sender must be 0
296  * \param[in]  sender             Expected sender node ID.
297  * \param[in]  application_id     Application ID this receiver instance handles (0 for node handler).
298  * \param[out] client_id          Client ID extracted from the message (0 if no ID extension).
299  * \param[out] payload            Pointer within \p buf to the plaintext payload.
300  * \param[out] payload_len        Capacity of \p payload (bytes).
301  * \param[out] metadata           Set to values needed to initialize a reply.
302  *
303  * \return SFCP_ERROR_SUCCESS on success;
304  *         SFCP_ERROR_NO_MSG_AVAILABLE if nothing to read;
305  *         SFCP_ERROR_BUFFER_TOO_SMALL / *_INVALID_* for validation failures.
306  *
307  * \note Decryption/authentication MUST be performed before returning payload to the caller
308  *       when crypto is used.
309  */
310 enum sfcp_error_t sfcp_receive_msg(uint8_t *buf, size_t buf_size,
311 				   bool any_sender, sfcp_node_id_t sender,
312 				   uint16_t application_id, uint16_t *client_id,
313 				   uint8_t **payload, size_t *payload_len,
314 				   struct sfcp_msg_metadata_t *metadata);
315 
316 /**
317  * \brief Receive a reply (polling mode).
318  *
319  * \details
320  * Retrieves the next available reply corresponding to \p metadata (by route), validates it,
321  * and exposes the plaintext payload pointer and capacity. If nothing is available, returns
322  * SFCP_ERROR_NO_REPLY_AVAILABLE (non-fatal).
323  *
324  * Validation rules enforced include:
325  * - Packet type MUST be REPLY (normal) or PROTOCOL_ERROR_REPLY (protocol error).
326  *   Error replies are never encrypted.
327  * - If the message used ID extension, the reply MUST carry the same client_id and application_id.
328  * - uses_cryptography MUST mirror the original message for normal replies.
329  *
330  * \param[in]  buf               Buffer to receive the packet.
331  * \param[in]  buf_size          Size of \p buf.
332  * \param[in]  metadata          Reply metadata captured at send time.
333  * \param[out] payload           Pointer within \p buf to the plaintext payload (if any).
334  * \param[out] payload_len       Capacity of \p payload (bytes).
335  *
336  * \return SFCP_ERROR_SUCCESS on success;
337  *         SFCP_ERROR_NO_REPLY_AVAILABLE if nothing to read;
338  *         SFCP_ERROR_BUFFER_TOO_SMALL / *_INVALID_* for validation failures.
339  *
340  * \note Decryption/authentication MUST be performed before returning payload to the caller
341  *       when crypto is used.
342  */
343 enum sfcp_error_t sfcp_receive_reply(uint8_t *buf, size_t buf_size,
344 				     struct sfcp_reply_metadata_t metadata,
345 				     uint8_t **payload, size_t *payload_len);
346 
347 /**
348  * \brief Look up the registered message handler for an Application ID.
349  *
350  * \param[in]  application_id  Application ID to route messages to (0 for the
351  *                             node-wide/default handler).
352  * \param[out] handler         On success, set to the registered handler.
353  *
354  * \return SFCP_ERROR_SUCCESS on success;
355  *         SFCP_ERROR_INVALID_APPLICATION_ID if no handler exists;
356  *         other errors as appropriate.
357  */
358 enum sfcp_error_t sfcp_get_msg_handler(uint16_t application_id,
359 				       sfcp_handler_t *handler);
360 
361 /**
362  * \brief Register (or replace) the message handler for an Application ID.
363  *
364  * \param[in] application_id  Application ID to associate with \p handler
365  *                            (0 for the node-wide/default handler).
366  * \param[in] handler         Callback to invoke when a message for this
367  *                            Application ID is received.
368  *
369  * \return SFCP_ERROR_SUCCESS on success; an error code otherwise.
370  */
371 enum sfcp_error_t sfcp_register_msg_handler(uint16_t application_id,
372 					    sfcp_handler_t handler);
373 
374 /**
375  * \brief Copy a buffered Message out of the internal queue (handler mode).
376  *
377  * \details
378  * On success this function:
379  *  - Performs any required decryption, authentication, and access-control checks
380  *    before exposing data to the caller.
381  *  - Copies the plaintext payload into \p payload (if \p payload_len >= size).
382  *  - Fills \p sender, \p client_id, \p needs_reply, and \p metadata so a reply
383  *    can be constructed later.
384  *  - Removes the Message from the internal buffer.
385  *
386  * On failure, the Message MUST NOT be removed from the buffer.
387  *
388  * \param[in]  buffer_handle  Handle previously delivered to a message handler.
389  * \param[out] sender         Set to the Sender node ID.
390  * \param[out] client_id      Set to the Client ID (0 if ID extension not used).
391  * \param[out] needs_reply    Set true if the Message requests a reply.
392  * \param[out] payload        Destination buffer for the plaintext payload
393  *                            (may be NULL if \p payload_len is 0).
394  * \param[in]  payload_len    Size in bytes of \p payload.
395  * \param[out] payload_size   Set to the number of payload bytes available.
396  * \param[out] metadata       Filled with values needed to initialize a reply.
397  *
398  * \return SFCP_ERROR_SUCCESS on success;
399  *         SFCP_ERROR_PAYLOAD_TOO_LARGE if \p payload is too small (Message
400  *         is retained internally);
401  *         SFCP_ERROR_INVALID_PACKET / *_INVALID_* on validation failure
402  *         (Message is retained);
403  *         other errors as appropriate.
404  */
405 enum sfcp_error_t
406 sfcp_pop_msg_from_buffer(sfcp_buffer_handle_t buffer_handle,
407 			 sfcp_node_id_t *sender, uint16_t *client_id,
408 			 bool *needs_reply, uint8_t *payload,
409 			 size_t payload_len, size_t *payload_size,
410 			 struct sfcp_msg_metadata_t *metadata);
411 
412 /**
413  * \brief Look up the registered reply handler for a client identifier.
414  *
415  * \param[in]  client_id  Client identifier used to route replies (0 when the
416  *                        ID extension is not used).
417  * \param[out] handler    On success, set to the registered handler.
418  *
419  * \return SFCP_ERROR_SUCCESS on success;
420  *         SFCP_ERROR_INVALID_CLIENT_ID if no handler exists;
421  *         other errors as appropriate.
422  */
423 enum sfcp_error_t sfcp_get_reply_handler(uint16_t client_id,
424 					 sfcp_handler_t *handler);
425 
426 /**
427  * \brief Register (or replace) the reply handler for an identifier.
428  *
429  * \details
430  * The identifier selects which replies are delivered to \p handler. In systems
431  * using the ID extension this is typically the \b client_id; otherwise it may be
432  * a single global handler registered with identifier 0.
433  *
434  * \param[in] application_id  Identifier used by the implementation to select
435  *                            the reply handler (commonly the client_id).
436  * \param[in] handler         Callback to invoke when a matching reply arrives.
437  *
438  * \return SFCP_ERROR_SUCCESS on success; an error code otherwise.
439  */
440 enum sfcp_error_t sfcp_register_reply_handler(uint16_t application_id,
441 					      sfcp_handler_t handler);
442 
443 /**
444  * \brief Copy a buffered Reply out of the internal queue (handler mode).
445  *
446  * \details
447  * On success this function:
448  *  - Performs any required decryption, authentication, and access-control checks
449  *    before exposing data to the caller.
450  *  - Copies the plaintext payload into \p payload (if \p payload_len >= size).
451  *  - Fills \p metadata so the caller can match the Reply to the original Message.
452  *  - Removes the Reply from the internal buffer.
453  *
454  * On failure, the Reply MUST NOT be removed from the buffer.
455  *
456  * \param[in]  buffer_handle  Handle previously delivered to a reply handler.
457  * \param[out] payload        Destination buffer for the plaintext payload
458  *                            (may be NULL if \p payload_len is 0).
459  * \param[in]  payload_len    Size in bytes of \p payload.
460  * \param[out] payload_size   Set to the number of payload bytes available.
461  * \param[out] metadata       Filled with the reply metadata (ids, message_id, flags).
462  *
463  * \return SFCP_ERROR_SUCCESS on success;
464  *         SFCP_ERROR_PAYLOAD_TOO_LARGE if \p payload is too small (Reply
465  *         is retained internally);
466  *         SFCP_ERROR_INVALID_PACKET / *_INVALID_* on validation failure
467  *         (Reply is retained);
468  *         other errors as appropriate.
469  */
470 enum sfcp_error_t
471 sfcp_pop_reply_from_buffer(sfcp_buffer_handle_t buffer_handle, uint8_t *payload,
472 			   size_t payload_len, size_t *payload_size,
473 			   struct sfcp_reply_metadata_t *metadata);
474 
475 #ifdef __cplusplus
476 }
477 #endif
478 
479 #endif /* __SFCP_H__ */
480