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