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