+#include "silc.h"
+
+/************************** Types and definitions ***************************/
+
+/* Packet engine */
+struct SilcPacketEngineStruct {
+ SilcRng rng; /* RNG for engine */
+ SilcPacketCallbacks *callbacks; /* Packet callbacks */
+ void *callback_context; /* Context for callbacks */
+ SilcList streams; /* All streams in engine */
+ SilcList packet_pool; /* Free list for received packets */
+ SilcMutex lock; /* Engine lock */
+ SilcBool local_is_router;
+};
+
+/* Packet procesor context */
+typedef struct SilcPacketProcessStruct {
+ SilcInt32 priority; /* Priority */
+ SilcPacketType *types; /* Packets to process */
+ SilcPacketCallbacks *callbacks; /* Callbacks or NULL */
+ void *callback_context;
+} *SilcPacketProcess;
+
+/* Packet stream */
+struct SilcPacketStreamStruct {
+ struct SilcPacketStreamStruct *next;
+ SilcPacketEngine engine; /* Packet engine */
+ SilcStream stream; /* Underlaying stream */
+ SilcMutex lock; /* Stream lock */
+ SilcDList process; /* Packet processors, it set */
+ SilcHashTable streamers; /* Valid if streamers exist */
+ void *stream_context; /* Stream context */
+ SilcBufferStruct inbuf; /* In buffer */
+ SilcBufferStruct outbuf; /* Out buffer */
+ SilcUInt32 send_psn; /* Sending sequence */
+ SilcCipher send_key; /* Sending key */
+ SilcHmac send_hmac; /* Sending HMAC */
+ SilcUInt32 receive_psn; /* Receiving sequence */
+ SilcCipher receive_key; /* Receiving key */
+ SilcHmac receive_hmac; /* Receiving HMAC */
+ unsigned char *src_id; /* Source ID */
+ unsigned char *dst_id; /* Destination ID */
+ unsigned int src_id_len : 6;
+ unsigned int src_id_type : 2;
+ unsigned int dst_id_len : 6;
+ unsigned int dst_id_type : 2;
+ SilcUInt8 refcnt; /* Reference counter */
+ unsigned int is_router : 1; /* Set if router stream */
+ unsigned int destroyed : 1; /* Set if destroyed */
+};
+
+/* Initial size of stream buffers */
+#define SILC_PACKET_DEFAULT_SIZE 1024
+
+/* Header length without source and destination ID's. */
+#define SILC_PACKET_HEADER_LEN 10
+
+/* Minimum length of SILC Packet Header. This much is decrypted always
+ when packet is received to be able to get all the relevant data out
+ from the header. */
+#define SILC_PACKET_MIN_HEADER_LEN 16
+
+/* Maximum padding length */
+#define SILC_PACKET_MAX_PADLEN 128
+
+/* Default padding length */
+#define SILC_PACKET_DEFAULT_PADLEN 16
+
+/* Minimum packet length */
+#define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
+
+
+/* Macros */
+
+/* Returns true length of the packet. */
+#define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
+do { \
+ SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
+ (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
+} while(0)
+
+/* Calculates the data length with given header length. This macro
+ can be used to check whether the data_len with header_len exceeds
+ SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
+ so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
+ plus header_len fits SILC_PACKET_MAX_LEN the returned data length
+ is the data_len given as argument. */
+#define SILC_PACKET_DATALEN(data_len, header_len) \
+ ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
+ data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
+
+/* Calculates the length of the padding in the packet. */
+#define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
+do { \
+ __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
+ ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
+ if (__padlen < 8) \
+ __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
+} while(0)
+
+/* Returns the length of the padding up to the maximum length, which
+ is 128 bytes.*/
+#define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
+do { \
+ __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
+ ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
+} while(0)
+
+/* EOS callback */
+#define SILC_PACKET_CALLBACK_EOS(s) \
+do { \
+ (s)->engine->callbacks->eos((s)->engine, s, \
+ (s)->engine->callback_context, \
+ (s)->stream_context); \
+} while(0)
+
+/* Error callback */
+#define SILC_PACKET_CALLBACK_ERROR(s, err) \
+do { \
+ (s)->engine->callbacks->error((s)->engine, s, err, \
+ (s)->engine->callback_context, \
+ (s)->stream_context); \
+} while(0)
+
+
+/************************ Static utility functions **************************/
+
+static void silc_packet_read_process(SilcPacketStream stream);
+
+/* Our stream IO notifier callback. */
+
+static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
+ void *context)
+{
+ SilcPacketStream ps = context;
+ int ret;