Added silc_packet_error_string.
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /*
20  * Created: Fri Jul 25 18:52:14 1997
21  */
22 /* $Id$ */
23
24 #include "silc.h"
25
26 /************************** Types and definitions ***************************/
27
28 /* Per scheduler (which usually means per thread) data.  We put per scheduler
29    data here for accessing without locking.  SILC Schedule dictates that
30    tasks are dispatched in one thread, hence the per scheduler context. */
31 typedef struct {
32   SilcSchedule schedule;                 /* The scheduler */
33   SilcPacketEngine engine;               /* Packet engine */
34   SilcDList inbufs;                      /* Data inbut buffer list */
35   SilcUInt32 stream_count;               /* Number of streams using this */
36 } *SilcPacketEngineContext;
37
38 /* Packet engine */
39 struct SilcPacketEngineStruct {
40   SilcMutex lock;                        /* Engine lock */
41   SilcRng rng;                           /* RNG for engine */
42   SilcHashTable contexts;                /* Per scheduler contexts */
43   SilcPacketCallbacks *callbacks;        /* Packet callbacks */
44   void *callback_context;                /* Context for callbacks */
45   SilcList streams;                      /* All streams in engine */
46   SilcList packet_pool;                  /* Free list for received packets */
47   SilcHashTable udp_remote;              /* UDP remote streams, or NULL */
48   unsigned int local_is_router    : 1;
49 };
50
51 /* Packet processor context */
52 typedef struct SilcPacketProcessStruct {
53   SilcPacketType *types;                 /* Packets to process */
54   SilcPacketCallbacks *callbacks;        /* Callbacks or NULL */
55   void *callback_context;
56   SilcInt32 priority;                    /* Priority */
57 } *SilcPacketProcess;
58
59 /* UDP remote stream tuple */
60 typedef struct {
61   char *remote_ip;                       /* Remote IP address */
62   SilcUInt16 remote_port;                /* Remote port */
63 } *SilcPacketRemoteUDP;
64
65 /* Packet stream */
66 struct SilcPacketStreamStruct {
67   struct SilcPacketStreamStruct *next;
68   SilcPacketEngineContext sc;            /* Per scheduler context */
69   SilcStream stream;                     /* Underlaying stream */
70   SilcMutex lock;                        /* Packet stream lock */
71   SilcDList process;                     /* Packet processors, or NULL */
72   SilcPacketRemoteUDP remote_udp;        /* UDP remote stream tuple, or NULL */
73   void *stream_context;                  /* Stream context */
74   SilcBufferStruct outbuf;               /* Out buffer */
75   SilcBuffer inbuf;                      /* Inbuf from inbuf list or NULL */
76   SilcCipher send_key[2];                /* Sending key */
77   SilcHmac send_hmac[2];                 /* Sending HMAC */
78   SilcCipher receive_key[2];             /* Receiving key */
79   SilcHmac receive_hmac[2];              /* Receiving HMAC */
80   unsigned char *src_id;                 /* Source ID */
81   unsigned char *dst_id;                 /* Destination ID */
82   SilcUInt32 send_psn;                   /* Sending sequence */
83   SilcUInt32 receive_psn;                /* Receiving sequence */
84   SilcAtomic8 refcnt;                    /* Reference counter */
85   SilcUInt8 sid;                         /* Security ID, set if IV included */
86   unsigned int src_id_len  : 6;
87   unsigned int src_id_type : 2;
88   unsigned int dst_id_len  : 6;
89   unsigned int dst_id_type : 2;
90   unsigned int is_router   : 1;          /* Set if router stream */
91   unsigned int destroyed   : 1;          /* Set if destroyed */
92   unsigned int iv_included : 1;          /* Set if IV included */
93   unsigned int udp         : 1;          /* UDP remote stream */
94 };
95
96 /* Initial size of stream buffers */
97 #define SILC_PACKET_DEFAULT_SIZE  1024
98
99 /* Header length without source and destination ID's. */
100 #define SILC_PACKET_HEADER_LEN 10
101
102 /* Minimum length of SILC Packet Header. */
103 #define SILC_PACKET_MIN_HEADER_LEN 16
104 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
105
106 /* Maximum padding length */
107 #define SILC_PACKET_MAX_PADLEN 128
108
109 /* Default padding length */
110 #define SILC_PACKET_DEFAULT_PADLEN 16
111
112 /* Minimum packet length */
113 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
114
115 /* Returns true length of the packet. */
116 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
117 do {                                                                     \
118   SILC_GET16_MSB((__ret_truelen), (__packetdata));                       \
119   (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4];    \
120 } while(0)
121
122 /* Calculates the data length with given header length.  This macro
123    can be used to check whether the data_len with header_len exceeds
124    SILC_PACKET_MAX_LEN.  If it does, this returns the new data_len
125    so that the SILC_PACKET_MAX_LEN is not exceeded.  If the data_len
126    plus header_len fits SILC_PACKET_MAX_LEN the returned data length
127    is the data_len given as argument. */
128 #define SILC_PACKET_DATALEN(data_len, header_len)                         \
129   ((data_len + header_len) > SILC_PACKET_MAX_LEN ?                        \
130    data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
131
132 /* Calculates the length of the padding in the packet. */
133 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen)               \
134 do {                                                                        \
135   __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) %                  \
136               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN));  \
137   if (__padlen < 8)                                                         \
138     __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
139 } while(0)
140
141 /* Returns the length of the padding up to the maximum length, which
142    is 128 bytes.*/
143 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen)          \
144 do {                                                                       \
145   __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) %                     \
146               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
147 } while(0)
148
149 /* EOS callback */
150 #define SILC_PACKET_CALLBACK_EOS(s)                                     \
151 do {                                                                    \
152   (s)->sc->engine->callbacks->eos((s)->sc->engine, s,                   \
153                                   (s)->sc->engine->callback_context,    \
154                                   (s)->stream_context);                 \
155 } while(0)
156
157 /* Error callback */
158 #define SILC_PACKET_CALLBACK_ERROR(s, err)                              \
159 do {                                                                    \
160   (s)->sc->engine->callbacks->error((s)->sc->engine, s, err,            \
161                                     (s)->sc->engine->callback_context,  \
162                                     (s)->stream_context);               \
163 } while(0)
164
165 static SilcBool silc_packet_dispatch(SilcPacket packet);
166 static void silc_packet_read_process(SilcPacketStream stream);
167 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
168                                             SilcPacketType type,
169                                             SilcPacketFlags flags,
170                                             SilcIdType src_id_type,
171                                             unsigned char *src_id,
172                                             SilcUInt32 src_id_len,
173                                             SilcIdType dst_id_type,
174                                             unsigned char *dst_id,
175                                             SilcUInt32 dst_id_len,
176                                             const unsigned char *data,
177                                             SilcUInt32 data_len,
178                                             SilcCipher cipher,
179                                             SilcHmac hmac);
180
181 /************************ Static utility functions **************************/
182
183 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
184
185 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
186 {
187   SilcPacket packet = context;
188   SilcPacketStream stream = packet->stream;
189
190   SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
191
192   silc_mutex_lock(stream->lock);
193   if (!stream->destroyed)
194     silc_packet_dispatch(packet);
195   silc_mutex_unlock(stream->lock);
196   silc_packet_stream_unref(stream);
197 }
198
199 /* Write data to the stream.  Must be called with ps->lock locked.  Unlocks
200    the lock inside this function, unless no_unlock is TRUE.  Unlocks always
201    in case it returns FALSE. */
202
203 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
204                                                 SilcBool no_unlock)
205 {
206   SilcStream stream;
207   SilcBool connected;
208   int i;
209
210   if (ps->udp)
211     stream = ((SilcPacketStream)ps->stream)->stream;
212   else
213     stream = ps->stream;
214
215   if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
216     if (!connected) {
217       /* Connectionless UDP stream */
218       while (silc_buffer_len(&ps->outbuf) > 0) {
219         i = silc_net_udp_send(stream, ps->remote_udp->remote_ip,
220                               ps->remote_udp->remote_port,
221                               ps->outbuf.data, silc_buffer_len(&ps->outbuf));
222         if (silc_unlikely(i == -2)) {
223           /* Error */
224           silc_buffer_reset(&ps->outbuf);
225           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
226           return FALSE;
227         }
228
229         if (silc_unlikely(i == -1)) {
230           /* Cannot write now, write later. */
231           if (!no_unlock)
232             silc_mutex_unlock(ps->lock);
233           return TRUE;
234         }
235
236         /* Wrote data */
237         silc_buffer_pull(&ps->outbuf, i);
238       }
239
240       silc_buffer_reset(&ps->outbuf);
241       if (!no_unlock)
242         silc_mutex_unlock(ps->lock);
243
244       return TRUE;
245     }
246   }
247
248   /* Write the data to the stream */
249   while (silc_buffer_len(&ps->outbuf) > 0) {
250     i = silc_stream_write(stream, ps->outbuf.data,
251                           silc_buffer_len(&ps->outbuf));
252     if (silc_unlikely(i == 0)) {
253       /* EOS */
254       silc_buffer_reset(&ps->outbuf);
255       silc_mutex_unlock(ps->lock);
256       SILC_PACKET_CALLBACK_EOS(ps);
257       return FALSE;
258     }
259
260     if (silc_unlikely(i == -2)) {
261       /* Error */
262       silc_buffer_reset(&ps->outbuf);
263       silc_mutex_unlock(ps->lock);
264       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
265       return FALSE;
266     }
267
268     if (silc_unlikely(i == -1)) {
269       /* Cannot write now, write later. */
270       if (!no_unlock)
271         silc_mutex_unlock(ps->lock);
272       return TRUE;
273     }
274
275     /* Wrote data */
276     silc_buffer_pull(&ps->outbuf, i);
277   }
278
279   silc_buffer_reset(&ps->outbuf);
280   if (!no_unlock)
281     silc_mutex_unlock(ps->lock);
282
283   return TRUE;
284 }
285
286 /* Reads data from stream.  Must be called with ps->lock locked.  If this
287    returns FALSE the lock has been unlocked.  If this returns packet stream
288    to `ret_ps' its lock has been acquired and `ps' lock has been unlocked.
289    It is returned if the stream is UDP and remote UDP stream exists for
290    the sender of the packet. */
291
292 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
293                                                SilcPacketStream *ret_ps)
294 {
295   SilcStream stream = ps->stream;
296   SilcBuffer inbuf;
297   SilcBool connected;
298   int ret;
299
300   /* Get inbuf.  If there is already some data for this stream in the buffer
301      we already have it.  Otherwise get the current one from list, it will
302      include the data. */
303   inbuf = ps->inbuf;
304   if (!inbuf) {
305     silc_dlist_start(ps->sc->inbufs);
306     inbuf = silc_dlist_get(ps->sc->inbufs);
307     if (!inbuf) {
308       /* Allocate new data input buffer */
309       inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
310       if (!inbuf) {
311         silc_mutex_unlock(ps->lock);
312         return FALSE;
313       }
314       silc_buffer_reset(inbuf);
315       silc_dlist_add(ps->sc->inbufs, inbuf);
316     }
317   }
318
319   /* Make sure there is enough room to read */
320   if (SILC_PACKET_DEFAULT_SIZE * 2 > silc_buffer_taillen(inbuf))
321     silc_buffer_realloc(inbuf, silc_buffer_truelen(inbuf) +
322                         (SILC_PACKET_DEFAULT_SIZE * 2));
323
324   if (silc_socket_stream_is_udp(stream, &connected)) {
325     if (!connected) {
326       /* Connectionless UDP stream, read one UDP packet */
327       char remote_ip[64], tuple[64];
328       int remote_port;
329       SilcPacketStream remote;
330
331       ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
332                                  &remote_port, inbuf->tail,
333                                  silc_buffer_taillen(inbuf));
334
335       if (silc_unlikely(ret < 0)) {
336         silc_mutex_unlock(ps->lock);
337         if (ret == -1) {
338           /* Cannot read now, do it later. */
339           silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
340           return FALSE;
341         }
342
343         /* Error */
344         silc_buffer_reset(inbuf);
345         SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
346         return FALSE;
347       }
348
349       /* See if remote packet stream exist for this sender */
350       silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
351       silc_mutex_lock(ps->sc->engine->lock);
352       if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
353                                (void *)&remote)) {
354         silc_mutex_unlock(ps->sc->engine->lock);
355         SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
356                         remote_port, remote));
357         silc_mutex_unlock(ps->lock);
358         silc_mutex_lock(remote->lock);
359         *ret_ps = remote;
360         return TRUE;
361       }
362       silc_mutex_unlock(ps->sc->engine->lock);
363
364       /* Unknown sender */
365       if (!ps->remote_udp) {
366         ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
367         if (silc_unlikely(!ps->remote_udp)) {
368           silc_mutex_unlock(ps->lock);
369           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
370           return FALSE;
371         }
372       }
373
374       /* Save sender IP and port */
375       silc_free(ps->remote_udp->remote_ip);
376       ps->remote_udp->remote_ip = strdup(remote_ip);
377       ps->remote_udp->remote_port = remote_port;
378
379       silc_buffer_pull_tail(inbuf, ret);
380       return TRUE;
381     }
382   }
383
384   /* Read data from the stream */
385   ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
386   if (silc_unlikely(ret <= 0)) {
387     silc_mutex_unlock(ps->lock);
388     if (ret == 0) {
389       /* EOS */
390       silc_buffer_reset(inbuf);
391       SILC_PACKET_CALLBACK_EOS(ps);
392       return FALSE;
393     }
394
395     if (ret == -1) {
396       /* Cannot read now, do it later. */
397       silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
398       return FALSE;
399     }
400
401     /* Error */
402     silc_buffer_reset(inbuf);
403     SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
404     return FALSE;
405   }
406
407   silc_buffer_pull_tail(inbuf, ret);
408   return TRUE;
409 }
410
411 /* Our stream IO notifier callback. */
412
413 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
414                                   void *context)
415 {
416   SilcPacketStream remote = NULL, ps = context;
417
418   silc_mutex_lock(ps->lock);
419
420   if (silc_unlikely(ps->destroyed)) {
421     silc_mutex_unlock(ps->lock);
422     return;
423   }
424
425   switch (status) {
426   case SILC_STREAM_CAN_READ:
427     /* Reading is locked also with stream->lock because we may be reading
428        at the same time other thread is writing to same underlaying stream. */
429     SILC_LOG_DEBUG(("Reading data from stream %p, ps %p", ps->stream, ps));
430
431     /* Read data from stream */
432     if (!silc_packet_stream_read(ps, &remote))
433       return;
434
435     /* Now process the data */
436     silc_packet_stream_ref(ps);
437     if (!remote) {
438       silc_packet_read_process(ps);
439       silc_mutex_unlock(ps->lock);
440     } else {
441       silc_packet_read_process(remote);
442       silc_mutex_unlock(remote->lock);
443     }
444     silc_packet_stream_unref(ps);
445     break;
446
447   case SILC_STREAM_CAN_WRITE:
448     SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
449                     ps->stream, ps));
450
451     if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
452       silc_mutex_unlock(ps->lock);
453       return;
454     }
455
456     /* Write pending data to stream */
457     silc_packet_stream_write(ps, FALSE);
458     break;
459
460   default:
461     silc_mutex_unlock(ps->lock);
462     break;
463   }
464 }
465
466 /* Allocate packet */
467
468 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
469 {
470   SilcPacket packet;
471
472   SILC_LOG_DEBUG(("Packet pool count %d",
473                   silc_list_count(engine->packet_pool)));
474
475   silc_mutex_lock(engine->lock);
476
477   /* Get packet from freelist or allocate new one. */
478   packet = silc_list_get(engine->packet_pool);
479   if (!packet) {
480     void *tmp;
481
482     silc_mutex_unlock(engine->lock);
483
484     packet = silc_calloc(1, sizeof(*packet));
485     if (silc_unlikely(!packet))
486       return NULL;
487
488     SILC_LOG_DEBUG(("Allocating new packet %p", packet));
489
490     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
491     if (silc_unlikely(!tmp)) {
492       silc_free(packet);
493       return NULL;
494     }
495     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
496     silc_buffer_reset(&packet->buffer);
497
498     return packet;
499   }
500
501   SILC_LOG_DEBUG(("Get packet %p", packet));
502
503   /* Delete from freelist */
504   silc_list_del(engine->packet_pool, packet);
505
506   silc_mutex_unlock(engine->lock);
507
508   return packet;
509 }
510
511 /* UDP remote stream hash table destructor */
512
513 static void silc_packet_engine_hash_destr(void *key, void *context,
514                                           void *user_context)
515 {
516   silc_free(key);
517 }
518
519 /* Per scheduler context hash table destructor */
520
521 static void silc_packet_engine_context_destr(void *key, void *context,
522                                              void *user_context)
523 {
524   SilcPacketEngineContext sc = context;
525   SilcBuffer buffer;
526
527   silc_dlist_start(sc->inbufs);
528   while ((buffer = silc_dlist_get(sc->inbufs))) {
529     silc_buffer_clear(buffer);
530     silc_buffer_free(buffer);
531     silc_dlist_del(sc->inbufs, buffer);
532   }
533
534   silc_dlist_uninit(sc->inbufs);
535   silc_free(sc);
536 }
537
538
539 /******************************** Packet API ********************************/
540
541 /* Allocate new packet engine */
542
543 SilcPacketEngine
544 silc_packet_engine_start(SilcRng rng, SilcBool router,
545                          SilcPacketCallbacks *callbacks,
546                          void *callback_context)
547 {
548   SilcPacketEngine engine;
549   SilcPacket packet;
550   int i;
551   void *tmp;
552
553   SILC_LOG_DEBUG(("Starting new packet engine"));
554
555   if (!callbacks)
556     return NULL;
557   if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
558     return NULL;
559
560   engine = silc_calloc(1, sizeof(*engine));
561   if (!engine)
562     return NULL;
563
564   engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
565                                            silc_packet_engine_context_destr,
566                                            engine, TRUE);
567   if (!engine->contexts) {
568     silc_free(engine);
569     return NULL;
570   }
571
572   engine->rng = rng;
573   engine->local_is_router = router;
574   engine->callbacks = callbacks;
575   engine->callback_context = callback_context;
576   silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
577   silc_mutex_alloc(&engine->lock);
578
579   /* Allocate packet free list */
580   silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
581   for (i = 0; i < 5; i++) {
582     packet = silc_calloc(1, sizeof(*packet));
583     if (!packet) {
584       silc_packet_engine_stop(engine);
585       return NULL;
586     }
587
588     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
589     if (!tmp) {
590       silc_packet_engine_stop(engine);
591       return NULL;
592     }
593     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
594     silc_buffer_reset(&packet->buffer);
595
596     silc_list_add(engine->packet_pool, packet);
597   }
598   silc_list_start(engine->packet_pool);
599
600   return engine;
601 }
602
603 /* Stop packet engine */
604
605 void silc_packet_engine_stop(SilcPacketEngine engine)
606 {
607   SilcPacket packet;
608
609   SILC_LOG_DEBUG(("Stopping packet engine"));
610
611   if (!engine)
612     return;
613
614   /* Free packet free list */
615   silc_list_start(engine->packet_pool);
616   while ((packet = silc_list_get(engine->packet_pool))) {
617     silc_buffer_purge(&packet->buffer);
618     silc_free(packet);
619   }
620
621   silc_hash_table_free(engine->contexts);
622   silc_mutex_free(engine->lock);
623   silc_free(engine);
624 }
625
626 static const char *packet_error[] = {
627   "Cannot read from stream",
628   "Cannot write to stream",
629   "Packet MAC failed",
630   "Packet decryption failed",
631   "Unknown SID",
632   "Packet is malformed",
633   "System out of memory",
634 };
635
636 /* Return packet error string */
637
638 const char *silc_packet_error_string(SilcPacketError error)
639 {
640   if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY)
641     return "";
642   return packet_error[error];
643 }
644
645 /* Return list of packet streams in the engine */
646
647 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
648 {
649   SilcDList list;
650   SilcPacketStream ps;
651
652   list = silc_dlist_init();
653   if (!list)
654     return NULL;
655
656   silc_mutex_lock(engine->lock);
657   silc_list_start(engine->streams);
658   while ((ps = silc_list_get(engine->streams)))
659     silc_dlist_add(list, ps);
660   silc_mutex_unlock(engine->lock);
661
662   return list;
663 }
664
665 /* Create new packet stream */
666
667 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
668                                            SilcSchedule schedule,
669                                            SilcStream stream)
670 {
671   SilcPacketStream ps;
672   SilcBuffer inbuf;
673   void *tmp;
674
675   SILC_LOG_DEBUG(("Creating new packet stream"));
676
677   if (!engine || !stream)
678     return NULL;
679
680   ps = silc_calloc(1, sizeof(*ps));
681   if (!ps)
682     return NULL;
683
684   ps->stream = stream;
685   silc_atomic_init8(&ps->refcnt, 1);
686   silc_mutex_alloc(&ps->lock);
687
688   /* Allocate out buffer */
689   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
690   if (!tmp) {
691     silc_packet_stream_destroy(ps);
692     return NULL;
693   }
694   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
695   silc_buffer_reset(&ps->outbuf);
696
697   /* Initialize packet procesors list */
698   ps->process = silc_dlist_init();
699   if (!ps->process) {
700     silc_packet_stream_destroy(ps);
701     return NULL;
702   }
703
704   silc_mutex_lock(engine->lock);
705
706   /* Add per scheduler context */
707   if (!silc_hash_table_find(engine->contexts, schedule, NULL,
708                             (void *)&ps->sc)) {
709     ps->sc = silc_calloc(1, sizeof(*ps->sc));
710     if (!ps->sc) {
711       silc_packet_stream_destroy(ps);
712       silc_mutex_unlock(engine->lock);
713       return NULL;
714     }
715     ps->sc->engine = engine;
716     ps->sc->schedule = schedule;
717
718     /* Allocate data input buffer */
719     inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
720     if (!inbuf) {
721       silc_free(ps->sc);
722       ps->sc = NULL;
723       silc_packet_stream_destroy(ps);
724       silc_mutex_unlock(engine->lock);
725       return NULL;
726     }
727     silc_buffer_reset(inbuf);
728
729     ps->sc->inbufs = silc_dlist_init();
730     if (!ps->sc->inbufs) {
731       silc_buffer_free(inbuf);
732       silc_free(ps->sc);
733       ps->sc = NULL;
734       silc_packet_stream_destroy(ps);
735       silc_mutex_unlock(engine->lock);
736       return NULL;
737     }
738     silc_dlist_add(ps->sc->inbufs, inbuf);
739
740     /* Add to per scheduler context hash table */
741     if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
742       silc_buffer_free(inbuf);
743       silc_dlist_del(ps->sc->inbufs, inbuf);
744       silc_free(ps->sc);
745       ps->sc = NULL;
746       silc_packet_stream_destroy(ps);
747       silc_mutex_unlock(engine->lock);
748       return NULL;
749     }
750   }
751   ps->sc->stream_count++;
752
753   /* Add the packet stream to engine */
754   silc_list_add(engine->streams, ps);
755
756   /* If this is UDP stream, allocate UDP remote stream hash table */
757   if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
758     engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
759                                                silc_hash_string_compare, NULL,
760                                                silc_packet_engine_hash_destr,
761                                                NULL, TRUE);
762
763   silc_mutex_unlock(engine->lock);
764
765   /* Set IO notifier callback.  This schedules this stream for I/O. */
766   if (!silc_stream_set_notifier(ps->stream, schedule,
767                                 silc_packet_stream_io, ps)) {
768     SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
769     silc_packet_stream_destroy(ps);
770     return NULL;
771   }
772
773   return ps;
774 }
775
776 /* Add new remote packet stream for UDP packet streams */
777
778 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
779                                                const char *remote_ip,
780                                                SilcUInt16 remote_port,
781                                                SilcPacket packet)
782 {
783   SilcPacketEngine engine = stream->sc->engine;
784   SilcPacketStream ps;
785   char *tuple;
786   void *tmp;
787
788   SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
789                   remote_ip, remote_port, stream));
790
791   if (!stream || !remote_ip || !remote_port)
792     return NULL;
793
794   if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
795     SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
796     return NULL;
797   }
798
799   ps = silc_calloc(1, sizeof(*ps));
800   if (!ps)
801     return NULL;
802   ps->sc = stream->sc;
803
804   silc_atomic_init8(&ps->refcnt, 1);
805   silc_mutex_alloc(&ps->lock);
806
807   /* Set the UDP packet stream as underlaying stream */
808   silc_packet_stream_ref(stream);
809   ps->stream = (SilcStream)stream;
810   ps->udp = TRUE;
811
812   /* Allocate out buffer */
813   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
814   if (!tmp) {
815     silc_packet_stream_destroy(ps);
816     return NULL;
817   }
818   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
819   silc_buffer_reset(&ps->outbuf);
820
821   /* Initialize packet procesors list */
822   ps->process = silc_dlist_init();
823   if (!ps->process) {
824     silc_packet_stream_destroy(ps);
825     return NULL;
826   }
827
828   /* Add to engine with this IP and port pair */
829   tuple = silc_format("%d%s", remote_port, remote_ip);
830   silc_mutex_lock(engine->lock);
831   if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
832     silc_mutex_unlock(engine->lock);
833     silc_packet_stream_destroy(ps);
834     return NULL;
835   }
836   silc_mutex_unlock(engine->lock);
837
838   /* Save remote IP and port pair */
839   ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
840   if (!ps->remote_udp) {
841     silc_packet_stream_destroy(ps);
842     return NULL;
843   }
844   ps->remote_udp->remote_port = remote_port;
845   ps->remote_udp->remote_ip = strdup(remote_ip);
846   if (!ps->remote_udp->remote_ip) {
847     silc_packet_stream_destroy(ps);
848     return NULL;
849   }
850
851   if (packet) {
852     /* Inject packet to the new stream */
853     packet->stream = ps;
854     silc_packet_stream_ref(ps);
855     silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
856                                    silc_packet_stream_inject_packet, packet,
857                                    0, 0);
858   }
859
860   return ps;
861 }
862
863 /* Destroy packet stream */
864
865 void silc_packet_stream_destroy(SilcPacketStream stream)
866 {
867   SilcPacketEngine engine;
868
869   if (!stream)
870     return;
871
872   if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
873     stream->destroyed = TRUE;
874
875     /* Close the underlaying stream */
876     if (!stream->udp && stream->stream)
877       silc_stream_close(stream->stream);
878     return;
879   }
880
881   SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
882
883   if (!stream->udp) {
884     /* Delete from engine */
885     engine = stream->sc->engine;
886     silc_mutex_lock(engine->lock);
887     silc_list_del(engine->streams, stream);
888
889     /* Remove per scheduler context, if it is not used anymore */
890     if (stream->sc) {
891       stream->sc->stream_count--;
892       if (!stream->sc->stream_count)
893         silc_hash_table_del(engine->contexts, stream->sc->schedule);
894     }
895     silc_mutex_unlock(engine->lock);
896
897     /* Destroy the underlaying stream */
898     if (stream->stream)
899       silc_stream_destroy(stream->stream);
900   } else {
901     /* Delete from UDP remote hash table */
902     char tuple[64];
903     engine = stream->sc->engine;
904     silc_snprintf(tuple, sizeof(tuple), "%d%s",
905                   stream->remote_udp->remote_port,
906                   stream->remote_udp->remote_ip);
907     silc_mutex_lock(engine->lock);
908     silc_hash_table_del(engine->udp_remote, tuple);
909     silc_mutex_unlock(engine->lock);
910
911     silc_free(stream->remote_udp->remote_ip);
912     silc_free(stream->remote_udp);
913
914     /* Unreference the underlaying packet stream */
915     silc_packet_stream_unref((SilcPacketStream)stream->stream);
916   }
917
918   /* Clear and free buffers */
919   silc_buffer_clear(&stream->outbuf);
920   silc_buffer_purge(&stream->outbuf);
921
922   if (stream->process) {
923     SilcPacketProcess p;
924     silc_dlist_start(stream->process);
925     while ((p = silc_dlist_get(stream->process))) {
926       silc_free(p->types);
927       silc_free(p);
928       silc_dlist_del(stream->process, p);
929     }
930     silc_dlist_uninit(stream->process);
931   }
932
933   /* Destroy ciphers and HMACs */
934   if (stream->send_key[0])
935     silc_cipher_free(stream->send_key[0]);
936   if (stream->receive_key[0])
937     silc_cipher_free(stream->receive_key[0]);
938   if (stream->send_hmac[0])
939     silc_hmac_free(stream->send_hmac[0]);
940   if (stream->receive_hmac[0])
941     silc_hmac_free(stream->receive_hmac[0]);
942   if (stream->send_key[1])
943     silc_cipher_free(stream->send_key[1]);
944   if (stream->receive_key[1])
945     silc_cipher_free(stream->receive_key[1]);
946   if (stream->send_hmac[1])
947     silc_hmac_free(stream->send_hmac[1]);
948   if (stream->receive_hmac[1])
949     silc_hmac_free(stream->receive_hmac[1]);
950
951   /* Free IDs */
952   silc_free(stream->src_id);
953   silc_free(stream->dst_id);
954
955   silc_atomic_uninit8(&stream->refcnt);
956   silc_mutex_free(stream->lock);
957   silc_free(stream);
958 }
959
960 /* Return TRUE if the stream is valid */
961
962 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
963 {
964   return stream->destroyed == FALSE;
965 }
966
967 /* Marks as router stream */
968
969 void silc_packet_stream_set_router(SilcPacketStream stream)
970 {
971   stream->is_router = TRUE;
972 }
973
974 /* Mark to include IV in ciphertext */
975
976 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
977 {
978   stream->iv_included = TRUE;
979 }
980
981 /* Links `callbacks' to `stream' for specified packet types */
982
983 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
984                                            SilcPacketCallbacks *callbacks,
985                                            void *callback_context,
986                                            int priority, va_list ap)
987 {
988   SilcPacketProcess p, e;
989   SilcInt32 packet_type;
990   int i;
991
992   SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
993
994   if (!callbacks)
995     return FALSE;
996   if (!callbacks->packet_receive)
997     return FALSE;
998
999   p = silc_calloc(1, sizeof(*p));
1000   if (!p)
1001     return FALSE;
1002
1003   p->priority = priority;
1004   p->callbacks = callbacks;
1005   p->callback_context = callback_context;
1006
1007   silc_mutex_lock(stream->lock);
1008
1009   if (!stream->process) {
1010     stream->process = silc_dlist_init();
1011     if (!stream->process) {
1012       silc_mutex_unlock(stream->lock);
1013       return FALSE;
1014     }
1015   }
1016
1017   /* According to priority set the procesor to correct position.  First
1018      entry has the highest priority */
1019   silc_dlist_start(stream->process);
1020   while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1021     if (p->priority > e->priority) {
1022       silc_dlist_insert(stream->process, p);
1023       break;
1024     }
1025   }
1026   if (!e)
1027     silc_dlist_add(stream->process, p);
1028
1029   /* Get packet types to process */
1030   i = 1;
1031   while (1) {
1032     packet_type = va_arg(ap, SilcInt32);
1033
1034     if (packet_type == SILC_PACKET_ANY)
1035       break;
1036
1037     if (packet_type == -1)
1038       break;
1039
1040     p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1041     if (!p->types) {
1042       silc_mutex_unlock(stream->lock);
1043       return FALSE;
1044     }
1045
1046     p->types[i - 1] = (SilcPacketType)packet_type;
1047     i++;
1048   }
1049   if (p->types)
1050     p->types[i - 1] = 0;
1051
1052   silc_mutex_unlock(stream->lock);
1053
1054   silc_packet_stream_ref(stream);
1055
1056   return TRUE;
1057 }
1058
1059 /* Links `callbacks' to `stream' for specified packet types */
1060
1061 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1062                                  SilcPacketCallbacks *callbacks,
1063                                  void *callback_context,
1064                                  int priority, ...)
1065 {
1066   va_list ap;
1067   SilcBool ret;
1068
1069   va_start(ap, priority);
1070   ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1071                                    priority, ap);
1072   va_end(ap);
1073
1074   return ret;
1075 }
1076
1077 /* Unlinks `callbacks' from `stream'. */
1078
1079 void silc_packet_stream_unlink(SilcPacketStream stream,
1080                                SilcPacketCallbacks *callbacks,
1081                                void *callback_context)
1082 {
1083   SilcPacketProcess p;
1084
1085   SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1086                   callbacks, stream));
1087
1088   silc_mutex_lock(stream->lock);
1089
1090   silc_dlist_start(stream->process);
1091   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1092     if (p->callbacks == callbacks &&
1093         p->callback_context == callback_context) {
1094       silc_dlist_del(stream->process, p);
1095       silc_free(p->types);
1096       silc_free(p);
1097       break;
1098     }
1099
1100   if (!silc_dlist_count(stream->process)) {
1101     silc_dlist_uninit(stream->process);
1102     stream->process = NULL;
1103   }
1104
1105   silc_mutex_unlock(stream->lock);
1106
1107   silc_packet_stream_unref(stream);
1108 }
1109
1110 /* Returns TRUE if stream is UDP stream */
1111
1112 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1113 {
1114   return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1115 }
1116
1117 /* Return packet sender IP and port for UDP packet stream */
1118
1119 SilcBool silc_packet_get_sender(SilcPacket packet,
1120                                 const char **sender_ip,
1121                                 SilcUInt16 *sender_port)
1122 {
1123   if (!packet->stream->remote_udp)
1124     return FALSE;
1125
1126   *sender_ip = packet->stream->remote_udp->remote_ip;
1127   *sender_port = packet->stream->remote_udp->remote_port;
1128
1129   return TRUE;
1130 }
1131
1132 /* Reference packet stream */
1133
1134 void silc_packet_stream_ref(SilcPacketStream stream)
1135 {
1136   silc_atomic_add_int8(&stream->refcnt, 1);
1137   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1138                   silc_atomic_get_int8(&stream->refcnt) - 1,
1139                   silc_atomic_get_int8(&stream->refcnt)));
1140 }
1141
1142 /* Unreference packet stream */
1143
1144 void silc_packet_stream_unref(SilcPacketStream stream)
1145 {
1146   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1147                   silc_atomic_get_int8(&stream->refcnt),
1148                   silc_atomic_get_int8(&stream->refcnt) - 1));
1149   if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1150     return;
1151   silc_atomic_add_int8(&stream->refcnt, 1);
1152   silc_packet_stream_destroy(stream);
1153 }
1154
1155 /* Return engine */
1156
1157 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1158 {
1159   return stream->sc->engine;
1160 }
1161
1162 /* Set application context for packet stream */
1163
1164 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1165 {
1166   silc_mutex_lock(stream->lock);
1167   stream->stream_context = stream_context;
1168   silc_mutex_unlock(stream->lock);
1169 }
1170
1171 /* Return application context from packet stream */
1172
1173 void *silc_packet_get_context(SilcPacketStream stream)
1174 {
1175   void *context;
1176   silc_mutex_lock(stream->lock);
1177   context = stream->stream_context;
1178   silc_mutex_unlock(stream->lock);
1179   return context;
1180 }
1181
1182 /* Change underlaying stream */
1183
1184 void silc_packet_stream_set_stream(SilcPacketStream ps,
1185                                    SilcStream stream)
1186 {
1187   if (ps->stream)
1188     silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1189   ps->stream = stream;
1190   silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1191                            ps);
1192 }
1193
1194 /* Return underlaying stream */
1195
1196 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1197 {
1198   return stream->stream;
1199 }
1200
1201 /* Set keys. */
1202
1203 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1204                               SilcCipher receive_key, SilcHmac send_hmac,
1205                               SilcHmac receive_hmac, SilcBool rekey)
1206 {
1207   SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1208
1209   /* If doing rekey, send REKEY_DONE packet */
1210   if (rekey) {
1211     /* This will take stream lock. */
1212     if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1213                               stream->src_id_type, stream->src_id,
1214                               stream->src_id_len, stream->dst_id_type,
1215                               stream->dst_id, stream->dst_id_len,
1216                               NULL, 0, stream->send_key[0],
1217                               stream->send_hmac[0]))
1218       return FALSE;
1219
1220     /* Write the packet to the stream */
1221     if (!silc_packet_stream_write(stream, TRUE))
1222       return FALSE;
1223   } else {
1224     silc_mutex_lock(stream->lock);
1225   }
1226
1227   /* In case IV Included is set, save the old keys */
1228   if (stream->iv_included) {
1229     if (stream->send_key[1] && send_key) {
1230       silc_cipher_free(stream->send_key[1]);
1231       stream->send_key[1] = stream->send_key[0];
1232     }
1233     if (stream->receive_key[1] && receive_key) {
1234       silc_cipher_free(stream->receive_key[1]);
1235       stream->receive_key[1] = stream->receive_key[0];
1236     }
1237     if (stream->send_hmac[1] && send_hmac) {
1238       silc_hmac_free(stream->send_hmac[1]);
1239       stream->send_hmac[1] = stream->send_hmac[0];
1240     }
1241     if (stream->receive_hmac[1] && receive_hmac) {
1242       silc_hmac_free(stream->receive_hmac[1]);
1243       stream->receive_hmac[1] = stream->receive_hmac[0];
1244     }
1245   } else {
1246     if (stream->send_key[0] && send_key)
1247       silc_cipher_free(stream->send_key[0]);
1248     if (stream->receive_key[0] && receive_key)
1249       silc_cipher_free(stream->receive_key[0]);
1250     if (stream->send_hmac[0] && send_hmac)
1251       silc_hmac_free(stream->send_hmac[0]);
1252     if (stream->receive_hmac[0] && receive_hmac)
1253       silc_hmac_free(stream->receive_hmac[0]);
1254   }
1255
1256   /* Set keys */
1257   if (send_key)
1258     stream->send_key[0] = send_key;
1259   if (receive_key)
1260     stream->receive_key[0] = receive_key;
1261   if (send_hmac)
1262     stream->send_hmac[0] = send_hmac;
1263   if (receive_hmac)
1264     stream->receive_hmac[0] = receive_hmac;
1265
1266   silc_mutex_unlock(stream->lock);
1267   return TRUE;
1268 }
1269
1270 /* Return current ciphers from packet stream */
1271
1272 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1273                               SilcCipher *send_key,
1274                               SilcCipher *receive_key,
1275                               SilcHmac *send_hmac,
1276                               SilcHmac *receive_hmac)
1277 {
1278   if (!stream->send_key[0] && !stream->receive_key[0] &&
1279       !stream->send_hmac[0] && !stream->receive_hmac[0])
1280     return FALSE;
1281
1282   silc_mutex_lock(stream->lock);
1283
1284   if (send_key)
1285     *send_key = stream->send_key[0];
1286   if (receive_key)
1287     *receive_key = stream->receive_key[0];
1288   if (send_hmac)
1289     *send_hmac = stream->send_hmac[0];
1290   if (receive_hmac)
1291     *receive_hmac = stream->receive_hmac[0];
1292
1293   silc_mutex_unlock(stream->lock);
1294
1295   return TRUE;
1296 }
1297
1298 /* Set SILC IDs to packet stream */
1299
1300 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1301                              SilcIdType src_id_type, const void *src_id,
1302                              SilcIdType dst_id_type, const void *dst_id)
1303 {
1304   SilcUInt32 len;
1305   unsigned char tmp[32];
1306
1307   if (!src_id && !dst_id)
1308     return FALSE;
1309
1310   SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1311
1312   silc_mutex_lock(stream->lock);
1313
1314   if (src_id) {
1315     silc_free(stream->src_id);
1316     if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1317       silc_mutex_unlock(stream->lock);
1318       return FALSE;
1319     }
1320     stream->src_id = silc_memdup(tmp, len);
1321     if (!stream->src_id) {
1322       silc_mutex_unlock(stream->lock);
1323       return FALSE;
1324     }
1325     stream->src_id_type = src_id_type;
1326     stream->src_id_len = len;
1327   }
1328
1329   if (dst_id) {
1330     silc_free(stream->dst_id);
1331     if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1332       silc_mutex_unlock(stream->lock);
1333       return FALSE;
1334     }
1335     stream->dst_id = silc_memdup(tmp, len);
1336     if (!stream->dst_id) {
1337       silc_mutex_unlock(stream->lock);
1338       return FALSE;
1339     }
1340     stream->dst_id_type = dst_id_type;
1341     stream->dst_id_len = len;
1342   }
1343
1344   silc_mutex_unlock(stream->lock);
1345
1346   return TRUE;
1347 }
1348
1349 /* Return IDs from the packet stream */
1350
1351 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1352                              SilcBool *src_id_set, SilcID *src_id,
1353                              SilcBool *dst_id_set, SilcID *dst_id)
1354 {
1355   if (src_id && stream->src_id) {
1356     (*src_id).type = stream->src_id_type;
1357     switch (stream->src_id_type) {
1358     case SILC_ID_CLIENT:
1359       (*src_id).u.client_id = *(SilcClientID *)stream->src_id;
1360       break;
1361     case SILC_ID_SERVER:
1362       (*src_id).u.server_id = *(SilcServerID *)stream->src_id;
1363       break;
1364     case SILC_ID_CHANNEL:
1365       (*src_id).u.channel_id = *(SilcChannelID *)stream->src_id;
1366       break;
1367     }
1368   }
1369   if (stream->src_id && src_id_set)
1370     *src_id_set = TRUE;
1371
1372   if (dst_id && stream->dst_id) {
1373     (*dst_id).type = stream->dst_id_type;
1374     switch (stream->dst_id_type) {
1375     case SILC_ID_CLIENT:
1376       (*dst_id).u.client_id = *(SilcClientID *)stream->dst_id;
1377       break;
1378     case SILC_ID_SERVER:
1379       (*dst_id).u.server_id = *(SilcServerID *)stream->dst_id;
1380       break;
1381     case SILC_ID_CHANNEL:
1382       (*dst_id).u.channel_id = *(SilcChannelID *)stream->dst_id;
1383       break;
1384     }
1385   }
1386   if (stream->dst_id && dst_id_set)
1387     *dst_id_set = TRUE;
1388
1389   return TRUE;
1390 }
1391
1392 /* Adds Security ID (SID) */
1393
1394 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1395 {
1396   if (!stream->iv_included)
1397     return FALSE;
1398
1399   SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1400
1401   stream->sid = sid;
1402   return TRUE;
1403 }
1404
1405 /* Free packet */
1406
1407 void silc_packet_free(SilcPacket packet)
1408 {
1409   SilcPacketStream stream = packet->stream;
1410
1411   SILC_LOG_DEBUG(("Freeing packet %p", packet));
1412
1413   /* Check for double free */
1414   SILC_ASSERT(packet->stream != NULL);
1415
1416   packet->stream = NULL;
1417   packet->src_id = packet->dst_id = NULL;
1418   silc_buffer_reset(&packet->buffer);
1419
1420   silc_mutex_lock(stream->sc->engine->lock);
1421
1422   /* Put the packet back to freelist */
1423   silc_list_add(stream->sc->engine->packet_pool, packet);
1424   if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1425     silc_list_start(stream->sc->engine->packet_pool);
1426
1427   silc_mutex_unlock(stream->sc->engine->lock);
1428 }
1429
1430 /****************************** Packet Sending ******************************/
1431
1432 /* Prepare outgoing data buffer for packet sending.  Returns the
1433    pointer to that buffer into the `packet'. */
1434
1435 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1436                                                 SilcUInt32 totlen,
1437                                                 SilcHmac hmac,
1438                                                 SilcBuffer packet)
1439 {
1440   unsigned char *oldptr;
1441   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1442
1443   totlen += mac_len;
1444
1445   /* Allocate more space if needed */
1446   if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1447     if (!silc_buffer_realloc(&stream->outbuf,
1448                              silc_buffer_truelen(&stream->outbuf) + totlen))
1449       return FALSE;
1450   }
1451
1452   /* Pull data area for the new packet, and return pointer to the start of
1453      the data area and save the pointer in to the `packet'.  MAC is pulled
1454      later after it's computed. */
1455   oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1456   silc_buffer_set(packet, oldptr, totlen);
1457   silc_buffer_push_tail(packet, mac_len);
1458
1459   return TRUE;
1460 }
1461
1462 /* Increments counter when encrypting in counter mode. */
1463
1464 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1465                                                   SilcCipher cipher,
1466                                                   unsigned char *ret_iv)
1467 {
1468   unsigned char *iv = silc_cipher_get_iv(cipher);
1469   SilcUInt32 pc1, pc2;
1470
1471   /* Increment 64-bit packet counter */
1472   SILC_GET32_MSB(pc1, iv + 4);
1473   SILC_GET32_MSB(pc2, iv + 8);
1474   if (++pc2 == 0)
1475     ++pc1;
1476   SILC_PUT32_MSB(pc1, iv + 4);
1477   SILC_PUT32_MSB(pc2, iv + 8);
1478
1479   /* Reset block counter */
1480   memset(iv + 12, 0, 4);
1481
1482   /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1483   if (stream->iv_included) {
1484     /* Get new nonce */
1485     ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1486     ret_iv[1] = ret_iv[0] + iv[4];
1487     ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1488     ret_iv[3] = ret_iv[0] + ret_iv[2];
1489     SILC_PUT32_MSB(pc2, ret_iv + 4);
1490     SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1491
1492     /* Set new nonce to counter block */
1493     memcpy(iv + 4, ret_iv, 4);
1494   }
1495
1496   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1497 }
1498
1499 /* Internal routine to assemble outgoing packet.  Assembles and encryptes
1500    the packet.  The silc_packet_stream_write needs to be called to send it
1501    after this returns TRUE. */
1502
1503 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1504                                             SilcPacketType type,
1505                                             SilcPacketFlags flags,
1506                                             SilcIdType src_id_type,
1507                                             unsigned char *src_id,
1508                                             SilcUInt32 src_id_len,
1509                                             SilcIdType dst_id_type,
1510                                             unsigned char *dst_id,
1511                                             SilcUInt32 dst_id_len,
1512                                             const unsigned char *data,
1513                                             SilcUInt32 data_len,
1514                                             SilcCipher cipher,
1515                                             SilcHmac hmac)
1516 {
1517   unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1518   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1519   int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1520   SilcBool ctr;
1521   SilcBufferStruct packet;
1522
1523   SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1524                   "data len %d", silc_get_packet_name(type), stream->send_psn,
1525                   flags, src_id_type, dst_id_type, data_len));
1526
1527   /* Get the true length of the packet. This is saved as payload length
1528      into the packet header.  This does not include the length of the
1529      padding. */
1530   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1531                                             src_id_len + dst_id_len));
1532   enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1533                       src_id_len + dst_id_len);
1534
1535   /* If using CTR mode, increment the counter */
1536   ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1537   if (ctr) {
1538     silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1539
1540     /* If IV is included, the SID, IV and sequence number is added to packet */
1541     if (stream->iv_included && cipher) {
1542       psnlen = sizeof(psn);
1543       ivlen = 8 + 1;
1544       iv[0] = stream->sid;
1545     }
1546   } else {
1547     /* If IV is included, the SID, IV and sequence number is added to packet */
1548     if (stream->iv_included && cipher) {
1549       psnlen = sizeof(psn);
1550       ivlen = block_len + 1;
1551       iv[0] = stream->sid;
1552       memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1553     }
1554   }
1555
1556   /* We automatically figure out the packet structure from the packet
1557      type and flags, and calculate correct length.  Private messages with
1558      private keys and channel messages are special packets as their
1559      payload is encrypted already. */
1560   if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1561       flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1562     /* Padding is calculated from header + IDs */
1563     if (!ctr)
1564       SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1565                           psnlen), block_len, padlen);
1566
1567     /* Length to encrypt, header + IDs + padding. */
1568     enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1569               padlen + psnlen);
1570
1571   } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1572     if (stream->sc->engine->local_is_router && stream->is_router) {
1573       /* Channel messages between routers are encrypted as normal packets.
1574          Padding is calculated from true length of the packet. */
1575       if (!ctr)
1576         SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1577
1578       enclen += padlen + psnlen;
1579     } else {
1580       /* Padding is calculated from header + IDs */
1581       if (!ctr)
1582         SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1583                             psnlen), block_len, padlen);
1584
1585       /* Length to encrypt, header + IDs + padding. */
1586       enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1587                 padlen + psnlen);
1588     }
1589   } else {
1590     /* Padding is calculated from true length of the packet */
1591     if (flags & SILC_PACKET_FLAG_LONG_PAD)
1592       SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1593     else if (!ctr)
1594       SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1595
1596     enclen += padlen + psnlen;
1597   }
1598
1599   /* Remove implementation specific flags */
1600   flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1601
1602   /* Get random padding */
1603   for (i = 0; i < padlen; i++) tmppad[i] =
1604     silc_rng_get_byte_fast(stream->sc->engine->rng);
1605
1606   silc_mutex_lock(stream->lock);
1607
1608   /* Get packet pointer from the outgoing buffer */
1609   if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1610                                               + psnlen, hmac, &packet))) {
1611     silc_mutex_unlock(stream->lock);
1612     return FALSE;
1613   }
1614
1615   SILC_PUT32_MSB(stream->send_psn, psn);
1616
1617   /* Create the packet.  This creates the SILC header, adds padding, and
1618      the actual packet data. */
1619   i = silc_buffer_format(&packet,
1620                          SILC_STR_DATA(iv, ivlen),
1621                          SILC_STR_DATA(psn, psnlen),
1622                          SILC_STR_UI_SHORT(truelen),
1623                          SILC_STR_UI_CHAR(flags),
1624                          SILC_STR_UI_CHAR(type),
1625                          SILC_STR_UI_CHAR(padlen),
1626                          SILC_STR_UI_CHAR(0),
1627                          SILC_STR_UI_CHAR(src_id_len),
1628                          SILC_STR_UI_CHAR(dst_id_len),
1629                          SILC_STR_UI_CHAR(src_id_type),
1630                          SILC_STR_DATA(src_id, src_id_len),
1631                          SILC_STR_UI_CHAR(dst_id_type),
1632                          SILC_STR_DATA(dst_id, dst_id_len),
1633                          SILC_STR_DATA(tmppad, padlen),
1634                          SILC_STR_DATA(data, data_len),
1635                          SILC_STR_END);
1636   if (silc_unlikely(i < 0)) {
1637     silc_mutex_unlock(stream->lock);
1638     return FALSE;
1639   }
1640
1641   SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1642                    silc_buffer_data(&packet), silc_buffer_len(&packet));
1643
1644   /* Encrypt the packet */
1645   if (silc_likely(cipher)) {
1646     SILC_LOG_DEBUG(("Encrypting packet"));
1647     silc_cipher_set_iv(cipher, NULL);
1648     if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1649                                            packet.data + ivlen, enclen,
1650                                            NULL))) {
1651       SILC_LOG_ERROR(("Packet encryption failed"));
1652       silc_mutex_unlock(stream->lock);
1653       return FALSE;
1654     }
1655   }
1656
1657   /* Compute HMAC */
1658   if (silc_likely(hmac)) {
1659     SilcUInt32 mac_len;
1660
1661     /* MAC is computed from the entire encrypted packet data, and put
1662        to the end of the packet. */
1663     silc_hmac_init(hmac);
1664     silc_hmac_update(hmac, psn, sizeof(psn));
1665     silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1666     silc_hmac_final(hmac, packet.tail, &mac_len);
1667     silc_buffer_pull_tail(&packet, mac_len);
1668     stream->send_psn++;
1669   }
1670
1671   return TRUE;
1672 }
1673
1674 /* Sends a packet */
1675
1676 SilcBool silc_packet_send(SilcPacketStream stream,
1677                           SilcPacketType type, SilcPacketFlags flags,
1678                           const unsigned char *data, SilcUInt32 data_len)
1679 {
1680   SilcBool ret;
1681
1682   ret = silc_packet_send_raw(stream, type, flags,
1683                              stream->src_id_type,
1684                              stream->src_id,
1685                              stream->src_id_len,
1686                              stream->dst_id_type,
1687                              stream->dst_id,
1688                              stream->dst_id_len,
1689                              data, data_len,
1690                              stream->send_key[0],
1691                              stream->send_hmac[0]);
1692
1693   /* Write the packet to the stream */
1694   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1695 }
1696
1697 /* Sends a packet, extended routine */
1698
1699 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1700                               SilcPacketType type, SilcPacketFlags flags,
1701                               SilcIdType src_id_type, void *src_id,
1702                               SilcIdType dst_id_type, void *dst_id,
1703                               const unsigned char *data, SilcUInt32 data_len,
1704                               SilcCipher cipher, SilcHmac hmac)
1705 {
1706   unsigned char src_id_data[32], dst_id_data[32];
1707   SilcUInt32 src_id_len, dst_id_len;
1708   SilcBool ret;
1709
1710   if (src_id)
1711     if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1712                         sizeof(src_id_data), &src_id_len))
1713       return FALSE;
1714   if (dst_id)
1715     if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1716                         sizeof(dst_id_data), &dst_id_len))
1717       return FALSE;
1718
1719   ret = silc_packet_send_raw(stream, type, flags,
1720                              src_id ? src_id_type : stream->src_id_type,
1721                              src_id ? src_id_data : stream->src_id,
1722                              src_id ? src_id_len : stream->src_id_len,
1723                              dst_id ? dst_id_type : stream->dst_id_type,
1724                              dst_id ? dst_id_data : stream->dst_id,
1725                              dst_id ? dst_id_len : stream->dst_id_len,
1726                              data, data_len,
1727                              cipher ? cipher : stream->send_key[0],
1728                              hmac ? hmac : stream->send_hmac[0]);
1729
1730   /* Write the packet to the stream */
1731   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1732 }
1733
1734 /* Sends packet after formatting the arguments to buffer */
1735
1736 SilcBool silc_packet_send_va(SilcPacketStream stream,
1737                              SilcPacketType type, SilcPacketFlags flags, ...)
1738 {
1739   SilcBufferStruct buf;
1740   SilcBool ret;
1741   va_list va;
1742
1743   va_start(va, flags);
1744
1745   memset(&buf, 0, sizeof(buf));
1746   if (silc_buffer_format_vp(&buf, va) < 0) {
1747     va_end(va);
1748     return FALSE;
1749   }
1750
1751   ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1752                          silc_buffer_len(&buf));
1753
1754   silc_buffer_purge(&buf);
1755   va_end(va);
1756
1757   return ret;
1758 }
1759
1760 /* Sends packet after formatting the arguments to buffer, extended routine */
1761
1762 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1763                                  SilcPacketType type, SilcPacketFlags flags,
1764                                  SilcIdType src_id_type, void *src_id,
1765                                  SilcIdType dst_id_type, void *dst_id,
1766                                  SilcCipher cipher, SilcHmac hmac, ...)
1767 {
1768   SilcBufferStruct buf;
1769   SilcBool ret;
1770   va_list va;
1771
1772   va_start(va, hmac);
1773
1774   memset(&buf, 0, sizeof(buf));
1775   if (silc_buffer_format_vp(&buf, va) < 0) {
1776     va_end(va);
1777     return FALSE;
1778   }
1779
1780   ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1781                              dst_id_type, dst_id, silc_buffer_data(&buf),
1782                              silc_buffer_len(&buf), cipher, hmac);
1783
1784   silc_buffer_purge(&buf);
1785   va_end(va);
1786
1787   return TRUE;
1788 }
1789
1790 /***************************** Packet Receiving *****************************/
1791
1792 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1793
1794 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1795                                              const unsigned char *data,
1796                                              SilcUInt32 data_len,
1797                                              const unsigned char *packet_mac,
1798                                              const unsigned char *packet_seq,
1799                                              SilcUInt32 sequence)
1800 {
1801   /* Check MAC */
1802   if (silc_likely(hmac)) {
1803     unsigned char mac[32], psn[4];
1804     SilcUInt32 mac_len;
1805
1806     SILC_LOG_DEBUG(("Verifying MAC"));
1807
1808     /* Compute HMAC of packet */
1809     silc_hmac_init(hmac);
1810
1811     if (!packet_seq) {
1812       SILC_PUT32_MSB(sequence, psn);
1813       silc_hmac_update(hmac, psn, 4);
1814     } else
1815       silc_hmac_update(hmac, packet_seq, 4);
1816
1817     silc_hmac_update(hmac, data, data_len);
1818     silc_hmac_final(hmac, mac, &mac_len);
1819
1820     /* Compare the MAC's */
1821     if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1822       SILC_LOG_DEBUG(("MAC failed"));
1823       return FALSE;
1824     }
1825
1826     SILC_LOG_DEBUG(("MAC is Ok"));
1827   }
1828
1829   return TRUE;
1830 }
1831
1832 /* Increments/sets counter when decrypting in counter mode. */
1833
1834 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1835                                                      unsigned char *iv,
1836                                                      unsigned char *packet_iv)
1837 {
1838   SilcUInt32 pc1, pc2;
1839
1840   /* If IV Included flag, set the IV from packet to block counter. */
1841   if (stream->iv_included) {
1842     memcpy(iv + 4, packet_iv, 8);
1843   } else {
1844     /* Increment 64-bit packet counter. */
1845     SILC_GET32_MSB(pc1, iv + 4);
1846     SILC_GET32_MSB(pc2, iv + 8);
1847     if (++pc2 == 0)
1848       ++pc1;
1849     SILC_PUT32_MSB(pc1, iv + 4);
1850     SILC_PUT32_MSB(pc2, iv + 8);
1851   }
1852
1853   /* Reset block counter */
1854   memset(iv + 12, 0, 4);
1855
1856   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1857 }
1858
1859 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
1860    Return 0 when packet is normal and 1 when it it special, -1 on error. */
1861
1862 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1863                                       SilcUInt32 sequence, SilcBuffer buffer,
1864                                       SilcBool normal)
1865 {
1866   if (normal == TRUE) {
1867     if (silc_likely(cipher)) {
1868       /* Decrypt rest of the packet */
1869       SILC_LOG_DEBUG(("Decrypting the packet"));
1870       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1871                                              buffer->data,
1872                                              silc_buffer_len(buffer), NULL)))
1873         return -1;
1874     }
1875     return 0;
1876
1877   } else {
1878     /* Decrypt rest of the header plus padding */
1879     if (silc_likely(cipher)) {
1880       SilcUInt16 len;
1881       SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1882
1883       SILC_LOG_DEBUG(("Decrypting the header"));
1884
1885       /* Padding length + src id len + dst id len + header length - 16
1886          bytes already decrypted, gives the rest of the encrypted packet */
1887       silc_buffer_push(buffer, block_len);
1888       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1889               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1890              block_len);
1891       silc_buffer_pull(buffer, block_len);
1892
1893       if (silc_unlikely(len > silc_buffer_len(buffer))) {
1894         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1895                         "packet dropped"));
1896         return -1;
1897       }
1898       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1899                                              buffer->data, len, NULL)))
1900         return -1;
1901     }
1902
1903     return 1;
1904   }
1905 }
1906
1907 /* Parses the packet. This is called when a whole packet is ready to be
1908    parsed. The buffer sent must be already decrypted before calling this
1909    function. */
1910
1911 static inline SilcBool silc_packet_parse(SilcPacket packet)
1912 {
1913   SilcBuffer buffer = &packet->buffer;
1914   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1915   SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1916   int ret;
1917
1918   SILC_LOG_DEBUG(("Parsing incoming packet"));
1919
1920   /* Parse the buffer.  This parses the SILC header of the packet. */
1921   ret = silc_buffer_unformat(buffer,
1922                              SILC_STR_ADVANCE,
1923                              SILC_STR_OFFSET(6),
1924                              SILC_STR_UI_CHAR(&src_id_len),
1925                              SILC_STR_UI_CHAR(&dst_id_len),
1926                              SILC_STR_UI_CHAR(&src_id_type),
1927                              SILC_STR_END);
1928   if (silc_unlikely(ret == -1)) {
1929     if (!packet->stream->udp &&
1930         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1931       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1932     return FALSE;
1933   }
1934
1935   if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1936                     dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1937     if (!packet->stream->udp &&
1938         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1939       SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1940                       packet->src_id_len, packet->dst_id_len));
1941     return FALSE;
1942   }
1943
1944   ret = silc_buffer_unformat(buffer,
1945                              SILC_STR_ADVANCE,
1946                              SILC_STR_DATA(&packet->src_id, src_id_len),
1947                              SILC_STR_UI_CHAR(&dst_id_type),
1948                              SILC_STR_DATA(&packet->dst_id, dst_id_len),
1949                              SILC_STR_OFFSET(padlen),
1950                              SILC_STR_END);
1951   if (silc_unlikely(ret == -1)) {
1952     if (!packet->stream->udp &&
1953         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1954       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1955     return FALSE;
1956   }
1957
1958   if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1959                     dst_id_type > SILC_ID_CHANNEL)) {
1960     if (!packet->stream->udp &&
1961         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1962       SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1963                       src_id_type, dst_id_type));
1964     return FALSE;
1965   }
1966
1967   packet->src_id_len = src_id_len;
1968   packet->dst_id_len = dst_id_len;
1969   packet->src_id_type = src_id_type;
1970   packet->dst_id_type = dst_id_type;
1971
1972   SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1973                    silc_buffer_len(buffer)), buffer->head,
1974                    silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1975
1976   SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1977                   silc_get_packet_name(packet->type)));
1978
1979   return TRUE;
1980 }
1981
1982 /* Dispatch packet to application.  Called with stream->lock locked.
1983    Returns FALSE if the stream was destroyed while dispatching a packet. */
1984
1985 static SilcBool silc_packet_dispatch(SilcPacket packet)
1986 {
1987   SilcPacketStream stream = packet->stream;
1988   SilcPacketProcess p;
1989   SilcBool default_sent = FALSE;
1990   SilcPacketType *pt;
1991
1992   /* Dispatch packet to all packet processors that want it */
1993
1994   if (silc_likely(!stream->process)) {
1995     /* Send to default processor as no others exist */
1996     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1997     silc_mutex_unlock(stream->lock);
1998     if (silc_unlikely(!stream->sc->engine->callbacks->
1999                       packet_receive(stream->sc->engine, stream, packet,
2000                                      stream->sc->engine->callback_context,
2001                                      stream->stream_context)))
2002       silc_packet_free(packet);
2003     silc_mutex_lock(stream->lock);
2004     return stream->destroyed == FALSE;
2005   }
2006
2007   silc_dlist_start(stream->process);
2008   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2009
2010     /* If priority is 0 or less, we send to default processor first
2011        because default processor has 0 priority */
2012     if (!default_sent && p->priority <= 0) {
2013       SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2014       default_sent = TRUE;
2015       silc_mutex_unlock(stream->lock);
2016       if (stream->sc->engine->callbacks->
2017           packet_receive(stream->sc->engine, stream, packet,
2018                          stream->sc->engine->callback_context,
2019                          stream->stream_context)) {
2020         silc_mutex_lock(stream->lock);
2021         return stream->destroyed == FALSE;
2022       }
2023       silc_mutex_lock(stream->lock);
2024     }
2025
2026     /* Send to processor */
2027     if (!p->types) {
2028       /* Send all packet types */
2029       SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2030       silc_mutex_unlock(stream->lock);
2031       if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2032                                        p->callback_context,
2033                                        stream->stream_context)) {
2034         silc_mutex_lock(stream->lock);
2035         return stream->destroyed == FALSE;
2036       }
2037       silc_mutex_lock(stream->lock);
2038     } else {
2039       /* Send specific types */
2040       for (pt = p->types; *pt; pt++) {
2041         if (*pt != packet->type)
2042           continue;
2043         SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2044         silc_mutex_unlock(stream->lock);
2045         if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2046                                          p->callback_context,
2047                                          stream->stream_context)) {
2048           silc_mutex_lock(stream->lock);
2049           return stream->destroyed == FALSE;
2050         }
2051         silc_mutex_lock(stream->lock);
2052         break;
2053       }
2054     }
2055   }
2056
2057   if (!default_sent) {
2058     /* Send to default processor as it has not been sent yet */
2059     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2060     silc_mutex_unlock(stream->lock);
2061     if (stream->sc->engine->callbacks->
2062         packet_receive(stream->sc->engine, stream, packet,
2063                        stream->sc->engine->callback_context,
2064                        stream->stream_context)) {
2065       silc_mutex_lock(stream->lock);
2066       return stream->destroyed == FALSE;
2067     }
2068     silc_mutex_lock(stream->lock);
2069   }
2070
2071   /* If we got here, no one wanted the packet, so drop it */
2072   silc_packet_free(packet);
2073   return stream->destroyed == FALSE;
2074 }
2075
2076 /* Process incoming data and parse packets.  Called with stream->lock
2077    locked. */
2078
2079 static void silc_packet_read_process(SilcPacketStream stream)
2080 {
2081   SilcBuffer inbuf;
2082   SilcCipher cipher;
2083   SilcHmac hmac;
2084   SilcPacket packet;
2085   SilcUInt8 sid;
2086   SilcUInt16 packetlen;
2087   SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2088   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2089   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2090   SilcBool normal;
2091   int ret;
2092
2093   /* Get inbuf.  If there is already some data for this stream in the buffer
2094      we already have it.  Otherwise get the current one from list, it will
2095      include the data. */
2096   inbuf = stream->inbuf;
2097   if (!inbuf) {
2098     silc_dlist_start(stream->sc->inbufs);
2099     inbuf = silc_dlist_get(stream->sc->inbufs);
2100   }
2101
2102   /* Parse the packets from the data */
2103   while (silc_buffer_len(inbuf) > 0) {
2104     ivlen = psnlen = 0;
2105     cipher = stream->receive_key[0];
2106     hmac = stream->receive_hmac[0];
2107     normal = FALSE;
2108
2109     if (silc_unlikely(silc_buffer_len(inbuf) <
2110                       (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2111                        SILC_PACKET_MIN_HEADER_LEN))) {
2112       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2113       silc_dlist_del(stream->sc->inbufs, inbuf);
2114       stream->inbuf = inbuf;
2115       return;
2116     }
2117
2118     if (silc_likely(hmac))
2119       mac_len = silc_hmac_len(hmac);
2120     else
2121       mac_len = 0;
2122
2123     /* Decrypt first block of the packet to get the length field out */
2124     if (silc_likely(cipher)) {
2125       block_len = silc_cipher_get_block_len(cipher);
2126
2127       if (stream->iv_included) {
2128         /* SID, IV and sequence number is included in the ciphertext */
2129         sid = (SilcUInt8)inbuf->data[0];
2130
2131         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2132           /* Set the CTR mode IV from packet to counter block */
2133           memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2134           silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2135           ivlen = 8 + 1;
2136         } else {
2137           /* Get IV from packet */
2138           memcpy(iv, inbuf->data + 1, block_len);
2139           ivlen = block_len + 1;
2140         }
2141         psnlen = 4;
2142
2143         /* Check SID, and get correct decryption key */
2144         if (sid != stream->sid) {
2145           /* If SID is recent get the previous key and use it */
2146           if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2147               stream->receive_key[1] && !stream->receive_hmac[1]) {
2148             cipher = stream->receive_key[1];
2149             hmac = stream->receive_hmac[1];
2150           } else {
2151             /* The SID is unknown, drop rest of the data in buffer */
2152             SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2153                             sid, stream->sid));
2154             silc_mutex_unlock(stream->lock);
2155             SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2156             silc_mutex_lock(stream->lock);
2157             goto out;
2158           }
2159         }
2160       } else {
2161         memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2162
2163         /* If using CTR mode, increment the counter */
2164         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2165           silc_packet_receive_ctr_increment(stream, iv, NULL);
2166       }
2167
2168       if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2169         silc_cipher_set_iv(cipher, NULL);
2170       silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2171
2172       header = tmp;
2173       if (stream->iv_included) {
2174         /* Take sequence number from packet */
2175         packet_seq = header;
2176         header += 4;
2177       }
2178     } else {
2179       /* Unencrypted packet */
2180       block_len = SILC_PACKET_MIN_HEADER_LEN;
2181       header = inbuf->data;
2182     }
2183
2184     /* Get packet length and full packet length with padding */
2185     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2186
2187     /* Sanity checks */
2188     if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2189       if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2190         SILC_LOG_ERROR(("Received too short packet"));
2191       silc_mutex_unlock(stream->lock);
2192       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2193       silc_mutex_lock(stream->lock);
2194       memset(tmp, 0, sizeof(tmp));
2195       goto out;
2196     }
2197
2198     if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2199       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2200                       "(%d bytes)",
2201                       paddedlen + mac_len - silc_buffer_len(inbuf)));
2202       memset(tmp, 0, sizeof(tmp));
2203       silc_dlist_del(stream->sc->inbufs, inbuf);
2204       stream->inbuf = inbuf;
2205       return;
2206     }
2207
2208     /* Check MAC of the packet */
2209     if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2210                                              paddedlen + ivlen,
2211                                              inbuf->data + ivlen +
2212                                              paddedlen, packet_seq,
2213                                              stream->receive_psn))) {
2214       silc_mutex_unlock(stream->lock);
2215       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2216       silc_mutex_lock(stream->lock);
2217       memset(tmp, 0, sizeof(tmp));
2218       goto out;
2219     }
2220
2221     /* Get packet */
2222     packet = silc_packet_alloc(stream->sc->engine);
2223     if (silc_unlikely(!packet)) {
2224       silc_mutex_unlock(stream->lock);
2225       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2226       silc_mutex_lock(stream->lock);
2227       memset(tmp, 0, sizeof(tmp));
2228       goto out;
2229     }
2230     packet->stream = stream;
2231
2232     /* Allocate more space to packet buffer, if needed */
2233     if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2234       if (!silc_buffer_realloc(&packet->buffer,
2235                                silc_buffer_truelen(&packet->buffer) +
2236                                (paddedlen -
2237                                 silc_buffer_truelen(&packet->buffer)))) {
2238         silc_mutex_unlock(stream->lock);
2239         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2240         silc_mutex_lock(stream->lock);
2241         silc_packet_free(packet);
2242         memset(tmp, 0, sizeof(tmp));
2243         goto out;
2244       }
2245     }
2246
2247     /* Parse packet header */
2248     packet->flags = (SilcPacketFlags)header[2];
2249     packet->type = (SilcPacketType)header[3];
2250
2251     if (stream->sc->engine->local_is_router) {
2252       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2253           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2254         normal = FALSE;
2255       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2256                (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2257                 stream->is_router == TRUE))
2258         normal = TRUE;
2259     } else {
2260       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2261           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2262         normal = FALSE;
2263       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2264         normal = TRUE;
2265     }
2266
2267     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2268                       stream->receive_psn, paddedlen + ivlen + mac_len),
2269                      inbuf->data, paddedlen + ivlen + mac_len);
2270
2271     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2272     silc_buffer_pull_tail(&packet->buffer, paddedlen);
2273     silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2274     silc_buffer_pull(&packet->buffer, block_len - psnlen);
2275     silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2276                                       psnlen + (block_len - psnlen)),
2277                     paddedlen - ivlen - psnlen - (block_len - psnlen));
2278     if (silc_likely(cipher)) {
2279       silc_cipher_set_iv(cipher, iv);
2280       ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2281                                 &packet->buffer, normal);
2282       if (silc_unlikely(ret < 0)) {
2283         silc_mutex_unlock(stream->lock);
2284         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2285         silc_mutex_lock(stream->lock);
2286         silc_packet_free(packet);
2287         memset(tmp, 0, sizeof(tmp));
2288         goto out;
2289       }
2290
2291       stream->receive_psn++;
2292     }
2293     silc_buffer_push(&packet->buffer, block_len);
2294
2295     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2296     silc_buffer_pull(inbuf, paddedlen + mac_len);
2297
2298     /* Parse the packet */
2299     if (silc_unlikely(!silc_packet_parse(packet))) {
2300       silc_mutex_unlock(stream->lock);
2301       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2302       silc_mutex_lock(stream->lock);
2303       silc_packet_free(packet);
2304       memset(tmp, 0, sizeof(tmp));
2305       goto out;
2306     }
2307
2308     /* Dispatch the packet to application */
2309     if (!silc_packet_dispatch(packet))
2310       break;
2311   }
2312
2313  out:
2314   /* Add inbuf back to free list, if we owned it. */
2315   if (stream->inbuf) {
2316     silc_dlist_add(stream->sc->inbufs, inbuf);
2317     stream->inbuf = NULL;
2318   }
2319
2320   silc_buffer_reset(inbuf);
2321 }
2322
2323 /****************************** Packet Waiting ******************************/
2324
2325 /* Packet wait receive callback */
2326 static SilcBool
2327 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2328                                 SilcPacketStream stream,
2329                                 SilcPacket packet,
2330                                 void *callback_context,
2331                                 void *stream_context);
2332
2333 /* Packet waiting callbacks */
2334 static SilcPacketCallbacks silc_packet_wait_cbs =
2335 {
2336   silc_packet_wait_packet_receive, NULL, NULL
2337 };
2338
2339 /* Packet waiting context */
2340 typedef struct {
2341   SilcMutex wait_lock;
2342   SilcCond wait_cond;
2343   SilcList packet_queue;
2344   unsigned int stopped     : 1;
2345 } *SilcPacketWait;
2346
2347 /* Packet wait receive callback */
2348
2349 static SilcBool
2350 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2351                                 SilcPacketStream stream,
2352                                 SilcPacket packet,
2353                                 void *callback_context,
2354                                 void *stream_context)
2355 {
2356   SilcPacketWait pw = callback_context;
2357
2358   /* Signal the waiting thread for a new packet */
2359   silc_mutex_lock(pw->wait_lock);
2360
2361   if (silc_unlikely(pw->stopped)) {
2362     silc_mutex_unlock(pw->wait_lock);
2363     return FALSE;
2364   }
2365
2366   silc_list_add(pw->packet_queue, packet);
2367   silc_cond_broadcast(pw->wait_cond);
2368
2369   silc_mutex_unlock(pw->wait_lock);
2370
2371   return TRUE;
2372 }
2373
2374 /* Initialize packet waiting */
2375
2376 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2377 {
2378   SilcPacketWait pw;
2379   SilcBool ret;
2380   va_list ap;
2381
2382   pw = silc_calloc(1, sizeof(*pw));
2383   if (!pw)
2384     return NULL;
2385
2386   /* Allocate mutex and conditional variable */
2387   if (!silc_mutex_alloc(&pw->wait_lock)) {
2388     silc_free(pw);
2389     return NULL;
2390   }
2391   if (!silc_cond_alloc(&pw->wait_cond)) {
2392     silc_mutex_free(pw->wait_lock);
2393     silc_free(pw);
2394     return NULL;
2395   }
2396
2397   /* Link to the packet stream for the requested packet types */
2398   va_start(ap, stream);
2399   ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2400                                    10000000, ap);
2401   va_end(ap);
2402   if (!ret) {
2403     silc_cond_free(pw->wait_cond);
2404     silc_mutex_free(pw->wait_lock);
2405     silc_free(pw);
2406     return NULL;
2407   }
2408
2409   /* Initialize packet queue */
2410   silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2411
2412   return (void *)pw;
2413 }
2414
2415 /* Uninitialize packet waiting */
2416
2417 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2418 {
2419   SilcPacketWait pw = waiter;
2420   SilcPacket packet;
2421
2422   /* Signal any threads to stop waiting */
2423   silc_mutex_lock(pw->wait_lock);
2424   pw->stopped = TRUE;
2425   silc_cond_broadcast(pw->wait_cond);
2426   silc_mutex_unlock(pw->wait_lock);
2427   silc_thread_yield();
2428
2429   /* Re-acquire lock and free resources */
2430   silc_mutex_lock(pw->wait_lock);
2431   silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2432
2433   /* Free any remaining packets */
2434   silc_list_start(pw->packet_queue);
2435   while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2436     silc_packet_free(packet);
2437
2438   silc_mutex_unlock(pw->wait_lock);
2439   silc_cond_free(pw->wait_cond);
2440   silc_mutex_free(pw->wait_lock);
2441   silc_free(pw);
2442 }
2443
2444 /* Blocks thread until a packet has been received. */
2445
2446 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2447 {
2448   SilcPacketWait pw = waiter;
2449   SilcBool ret = FALSE;
2450
2451   silc_mutex_lock(pw->wait_lock);
2452
2453   /* Wait here until packet has arrived */
2454   while (silc_list_count(pw->packet_queue) == 0) {
2455     if (silc_unlikely(pw->stopped)) {
2456       silc_mutex_unlock(pw->wait_lock);
2457       return -1;
2458     }
2459     ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2460   }
2461
2462   /* Return packet */
2463   silc_list_start(pw->packet_queue);
2464   *return_packet = silc_list_get(pw->packet_queue);
2465   silc_list_del(pw->packet_queue, *return_packet);
2466
2467   silc_mutex_unlock(pw->wait_lock);
2468
2469   return ret == TRUE ? 1 : 0;
2470 }
2471
2472 /************************** Packet Stream Wrapper ***************************/
2473
2474 /* Packet stream wrapper receive callback */
2475 static SilcBool
2476 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2477                                 SilcPacketStream stream,
2478                                 SilcPacket packet,
2479                                 void *callback_context,
2480                                 void *stream_context);
2481
2482 const SilcStreamOps silc_packet_stream_ops;
2483
2484 /* Packet stream wrapper context */
2485 typedef struct {
2486   const SilcStreamOps *ops;
2487   SilcPacketStream stream;
2488   SilcMutex lock;
2489   void *waiter;                   /* Waiter context in blocking mode */
2490   SilcPacketWrapCoder coder;
2491   void *coder_context;
2492   SilcBuffer encbuf;
2493   SilcStreamNotifier callback;
2494   void *context;
2495   SilcList in_queue;
2496   SilcPacketType type;
2497   SilcPacketFlags flags;
2498   unsigned int closed        : 1;
2499   unsigned int blocking      : 1;
2500   unsigned int read_more     : 1;
2501 } *SilcPacketWrapperStream;
2502
2503 /* Packet wrapper callbacks */
2504 static SilcPacketCallbacks silc_packet_wrap_cbs =
2505 {
2506   silc_packet_wrap_packet_receive, NULL, NULL
2507 };
2508
2509 /* Packet stream wrapper receive callback, non-blocking mode */
2510
2511 static SilcBool
2512 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2513                                 SilcPacketStream stream,
2514                                 SilcPacket packet,
2515                                 void *callback_context,
2516                                 void *stream_context)
2517 {
2518   SilcPacketWrapperStream pws = callback_context;
2519
2520   if (pws->closed || !pws->callback)
2521     return FALSE;
2522
2523   silc_mutex_lock(pws->lock);
2524   silc_list_add(pws->in_queue, packet);
2525   silc_mutex_unlock(pws->lock);
2526
2527   /* Call notifier callback */
2528   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2529
2530   return TRUE;
2531 }
2532
2533 /* Task callback to notify more data is available for reading */
2534
2535 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2536 {
2537   SilcPacketWrapperStream pws = context;
2538
2539   if (pws->closed || !pws->callback)
2540     return;
2541
2542   /* Call notifier callback */
2543   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2544 }
2545
2546 /* Read SILC packet */
2547
2548 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2549                           SilcUInt32 buf_len)
2550 {
2551   SilcPacketWrapperStream pws = stream;
2552   SilcPacket packet;
2553   SilcBool read_more = FALSE;
2554   int len;
2555
2556   if (pws->closed)
2557     return -2;
2558
2559   if (pws->blocking) {
2560     /* Block until packet is received */
2561     if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2562       return -2;
2563     if (pws->closed)
2564       return -2;
2565   } else {
2566     /* Non-blocking mode */
2567     silc_mutex_lock(pws->lock);
2568     if (!silc_list_count(pws->in_queue)) {
2569       silc_mutex_unlock(pws->lock);
2570       return -1;
2571     }
2572
2573     silc_list_start(pws->in_queue);
2574     packet = silc_list_get(pws->in_queue);
2575     silc_list_del(pws->in_queue, packet);
2576     silc_mutex_unlock(pws->lock);
2577   }
2578
2579   /* Call decoder if set */
2580   if (pws->coder && !pws->read_more)
2581     pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2582                pws->coder_context);
2583
2584   len = silc_buffer_len(&packet->buffer);
2585   if (len > buf_len) {
2586     len = buf_len;
2587     read_more = TRUE;
2588   }
2589
2590   /* Read data */
2591   memcpy(buf, packet->buffer.data, len);
2592
2593   if (read_more && !pws->blocking) {
2594     /* More data will be available (in blocking mode not supported). */
2595     silc_buffer_pull(&packet->buffer, len);
2596     silc_list_insert(pws->in_queue, NULL, packet);
2597     silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2598                                    silc_packet_wrap_read_more, pws, 0, 0);
2599     pws->read_more = TRUE;
2600     return len;
2601   }
2602
2603   pws->read_more = FALSE;
2604   silc_packet_free(packet);
2605   return len;
2606 }
2607
2608 /* Write SILC packet */
2609
2610 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2611                            SilcUInt32 data_len)
2612 {
2613   SilcPacketWrapperStream pws = stream;
2614   SilcBool ret = FALSE;
2615
2616   /* Call encoder if set */
2617   if (pws->coder) {
2618     silc_buffer_reset(pws->encbuf);
2619     ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2620                      pws->coder_context);
2621   }
2622
2623   /* Send the SILC packet */
2624   if (ret) {
2625     if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2626                              SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2627                                            silc_buffer_len(pws->encbuf)),
2628                              SILC_STR_DATA(data, data_len),
2629                              SILC_STR_END))
2630       return -2;
2631   } else {
2632     if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2633       return -2;
2634   }
2635
2636   return data_len;
2637 }
2638
2639 /* Close stream */
2640
2641 SilcBool silc_packet_wrap_close(SilcStream stream)
2642 {
2643   SilcPacketWrapperStream pws = stream;
2644
2645   if (pws->closed)
2646     return TRUE;
2647
2648   if (pws->blocking) {
2649     /* Close packet waiter */
2650     silc_packet_wait_uninit(pws->waiter, pws->stream);
2651   } else {
2652     /* Unlink */
2653     if (pws->callback)
2654       silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2655   }
2656   pws->closed = TRUE;
2657
2658   return TRUE;
2659 }
2660
2661 /* Destroy wrapper stream */
2662
2663 void silc_packet_wrap_destroy(SilcStream stream)
2664
2665 {
2666   SilcPacketWrapperStream pws = stream;
2667   SilcPacket packet;
2668
2669   SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2670
2671   silc_stream_close(stream);
2672   silc_list_start(pws->in_queue);
2673   while ((packet = silc_list_get(pws->in_queue)))
2674     silc_packet_free(packet);
2675   if (pws->lock)
2676     silc_mutex_free(pws->lock);
2677   if (pws->encbuf)
2678     silc_buffer_free(pws->encbuf);
2679   silc_packet_stream_unref(pws->stream);
2680
2681   silc_free(pws);
2682 }
2683
2684 /* Link stream to receive packets */
2685
2686 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2687                                    SilcSchedule schedule,
2688                                    SilcStreamNotifier callback,
2689                                    void *context)
2690 {
2691   SilcPacketWrapperStream pws = stream;
2692
2693   if (pws->closed || pws->blocking)
2694     return FALSE;
2695
2696   /* Link to receive packets */
2697   if (callback)
2698     silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2699                             100000, pws->type, -1);
2700   else
2701     silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2702
2703   pws->callback = callback;
2704   pws->context = context;
2705
2706   return TRUE;
2707 }
2708
2709 /* Return schedule */
2710
2711 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2712 {
2713   return NULL;
2714 }
2715
2716 /* Wraps packet stream into SilcStream. */
2717
2718 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2719                                    SilcPacketType type,
2720                                    SilcPacketFlags flags,
2721                                    SilcBool blocking_mode,
2722                                    SilcPacketWrapCoder coder,
2723                                    void *context)
2724 {
2725   SilcPacketWrapperStream pws;
2726
2727   pws = silc_calloc(1, sizeof(*pws));
2728   if (!pws)
2729     return NULL;
2730
2731   SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2732
2733   pws->ops = &silc_packet_stream_ops;
2734   pws->stream = stream;
2735   pws->type = type;
2736   pws->flags = flags;
2737   pws->blocking = blocking_mode;
2738   pws->coder = coder;
2739   pws->coder_context = context;
2740
2741   /* Allocate small amount for encoder buffer. */
2742   if (pws->coder)
2743     pws->encbuf = silc_buffer_alloc(8);
2744
2745   if (pws->blocking) {
2746     /* Blocking mode.  Use packet waiter to do the thing. */
2747     pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2748     if (!pws->waiter) {
2749       silc_free(pws);
2750       return NULL;
2751     }
2752   } else {
2753     /* Non-blocking mode */
2754     silc_mutex_alloc(&pws->lock);
2755     silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2756   }
2757
2758   silc_packet_stream_ref(stream);
2759
2760   return (SilcStream)pws;
2761 }
2762
2763 const SilcStreamOps silc_packet_stream_ops =
2764 {
2765   silc_packet_wrap_read,
2766   silc_packet_wrap_write,
2767   silc_packet_wrap_close,
2768   silc_packet_wrap_destroy,
2769   silc_packet_wrap_notifier,
2770   silc_packet_wrap_get_schedule,
2771 };