Added debugs.
[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   /* Increment 64-bit packet counter */
1475   SILC_GET32_MSB(pc1, iv + 4);
1476   SILC_GET32_MSB(pc2, iv + 8);
1477   if (++pc2 == 0)
1478     ++pc1;
1479   SILC_PUT32_MSB(pc1, iv + 4);
1480   SILC_PUT32_MSB(pc2, iv + 8);
1481
1482   /* Reset block counter */
1483   memset(iv + 12, 0, 4);
1484
1485   /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1486   if (stream->iv_included) {
1487     /* Get new nonce */
1488     ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1489     ret_iv[1] = ret_iv[0] + iv[4];
1490     ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1491     ret_iv[3] = ret_iv[0] + ret_iv[2];
1492     SILC_PUT32_MSB(pc2, ret_iv + 4);
1493     SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1494
1495     /* Set new nonce to counter block */
1496     memcpy(iv + 4, ret_iv, 4);
1497   }
1498
1499   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1500 }
1501
1502 /* Internal routine to assemble outgoing packet.  Assembles and encryptes
1503    the packet.  The silc_packet_stream_write needs to be called to send it
1504    after this returns TRUE. */
1505
1506 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1507                                             SilcPacketType type,
1508                                             SilcPacketFlags flags,
1509                                             SilcIdType src_id_type,
1510                                             unsigned char *src_id,
1511                                             SilcUInt32 src_id_len,
1512                                             SilcIdType dst_id_type,
1513                                             unsigned char *dst_id,
1514                                             SilcUInt32 dst_id_len,
1515                                             const unsigned char *data,
1516                                             SilcUInt32 data_len,
1517                                             SilcCipher cipher,
1518                                             SilcHmac hmac)
1519 {
1520   unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1521   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1522   int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1523   SilcBool ctr;
1524   SilcBufferStruct packet;
1525
1526   SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1527                   "data len %d", silc_get_packet_name(type), stream->send_psn,
1528                   flags, src_id_type, dst_id_type, data_len));
1529
1530   /* Get the true length of the packet. This is saved as payload length
1531      into the packet header.  This does not include the length of the
1532      padding. */
1533   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1534                                             src_id_len + dst_id_len));
1535   enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1536                       src_id_len + dst_id_len);
1537
1538   /* If using CTR mode, increment the counter */
1539   ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1540   if (ctr) {
1541     silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1542
1543     /* If IV is included, the SID, IV and sequence number is added to packet */
1544     if (stream->iv_included && cipher) {
1545       psnlen = sizeof(psn);
1546       ivlen = 8 + 1;
1547       iv[0] = stream->sid;
1548     }
1549   } else {
1550     /* If IV is included, the SID, IV and sequence number is added to packet */
1551     if (stream->iv_included && cipher) {
1552       psnlen = sizeof(psn);
1553       ivlen = block_len + 1;
1554       iv[0] = stream->sid;
1555       memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1556     }
1557   }
1558
1559   /* We automatically figure out the packet structure from the packet
1560      type and flags, and calculate correct length.  Private messages with
1561      private keys and channel messages are special packets as their
1562      payload is encrypted already. */
1563   if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1564       flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1565     /* Padding is calculated from header + IDs */
1566     if (!ctr)
1567       SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1568                           psnlen), block_len, padlen);
1569
1570     /* Length to encrypt, header + IDs + padding. */
1571     enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1572               padlen + psnlen);
1573
1574   } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1575     if (stream->sc->engine->local_is_router && stream->is_router) {
1576       /* Channel messages between routers are encrypted as normal packets.
1577          Padding is calculated from true length of the packet. */
1578       if (!ctr)
1579         SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1580
1581       enclen += padlen + psnlen;
1582     } else {
1583       /* Padding is calculated from header + IDs */
1584       if (!ctr)
1585         SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1586                             psnlen), block_len, padlen);
1587
1588       /* Length to encrypt, header + IDs + padding. */
1589       enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1590                 padlen + psnlen);
1591     }
1592   } else {
1593     /* Padding is calculated from true length of the packet */
1594     if (flags & SILC_PACKET_FLAG_LONG_PAD)
1595       SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1596     else if (!ctr)
1597       SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1598
1599     enclen += padlen + psnlen;
1600   }
1601
1602   /* Remove implementation specific flags */
1603   flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1604
1605   /* Get random padding */
1606   for (i = 0; i < padlen; i++) tmppad[i] =
1607     silc_rng_get_byte_fast(stream->sc->engine->rng);
1608
1609   silc_mutex_lock(stream->lock);
1610
1611   /* Get packet pointer from the outgoing buffer */
1612   if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1613                                               + psnlen, hmac, &packet))) {
1614     silc_mutex_unlock(stream->lock);
1615     return FALSE;
1616   }
1617
1618   SILC_PUT32_MSB(stream->send_psn, psn);
1619
1620   /* Create the packet.  This creates the SILC header, adds padding, and
1621      the actual packet data. */
1622   i = silc_buffer_format(&packet,
1623                          SILC_STR_DATA(iv, ivlen),
1624                          SILC_STR_DATA(psn, psnlen),
1625                          SILC_STR_UI_SHORT(truelen),
1626                          SILC_STR_UI_CHAR(flags),
1627                          SILC_STR_UI_CHAR(type),
1628                          SILC_STR_UI_CHAR(padlen),
1629                          SILC_STR_UI_CHAR(0),
1630                          SILC_STR_UI_CHAR(src_id_len),
1631                          SILC_STR_UI_CHAR(dst_id_len),
1632                          SILC_STR_UI_CHAR(src_id_type),
1633                          SILC_STR_DATA(src_id, src_id_len),
1634                          SILC_STR_UI_CHAR(dst_id_type),
1635                          SILC_STR_DATA(dst_id, dst_id_len),
1636                          SILC_STR_DATA(tmppad, padlen),
1637                          SILC_STR_DATA(data, data_len),
1638                          SILC_STR_END);
1639   if (silc_unlikely(i < 0)) {
1640     silc_mutex_unlock(stream->lock);
1641     return FALSE;
1642   }
1643
1644   SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1645                    silc_buffer_data(&packet), silc_buffer_len(&packet));
1646
1647   /* Encrypt the packet */
1648   if (silc_likely(cipher)) {
1649     SILC_LOG_DEBUG(("Encrypting packet"));
1650     silc_cipher_set_iv(cipher, NULL);
1651     if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1652                                            packet.data + ivlen, enclen,
1653                                            NULL))) {
1654       SILC_LOG_ERROR(("Packet encryption failed"));
1655       silc_mutex_unlock(stream->lock);
1656       return FALSE;
1657     }
1658   }
1659
1660   /* Compute HMAC */
1661   if (silc_likely(hmac)) {
1662     SilcUInt32 mac_len;
1663
1664     /* MAC is computed from the entire encrypted packet data, and put
1665        to the end of the packet. */
1666     silc_hmac_init(hmac);
1667     silc_hmac_update(hmac, psn, sizeof(psn));
1668     silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1669     silc_hmac_final(hmac, packet.tail, &mac_len);
1670     silc_buffer_pull_tail(&packet, mac_len);
1671     stream->send_psn++;
1672   }
1673
1674   return TRUE;
1675 }
1676
1677 /* Sends a packet */
1678
1679 SilcBool silc_packet_send(SilcPacketStream stream,
1680                           SilcPacketType type, SilcPacketFlags flags,
1681                           const unsigned char *data, SilcUInt32 data_len)
1682 {
1683   SilcBool ret;
1684
1685   ret = silc_packet_send_raw(stream, type, flags,
1686                              stream->src_id_type,
1687                              stream->src_id,
1688                              stream->src_id_len,
1689                              stream->dst_id_type,
1690                              stream->dst_id,
1691                              stream->dst_id_len,
1692                              data, data_len,
1693                              stream->send_key[0],
1694                              stream->send_hmac[0]);
1695
1696   /* Write the packet to the stream */
1697   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1698 }
1699
1700 /* Sends a packet, extended routine */
1701
1702 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1703                               SilcPacketType type, SilcPacketFlags flags,
1704                               SilcIdType src_id_type, void *src_id,
1705                               SilcIdType dst_id_type, void *dst_id,
1706                               const unsigned char *data, SilcUInt32 data_len,
1707                               SilcCipher cipher, SilcHmac hmac)
1708 {
1709   unsigned char src_id_data[32], dst_id_data[32];
1710   SilcUInt32 src_id_len, dst_id_len;
1711   SilcBool ret;
1712
1713   if (src_id)
1714     if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1715                         sizeof(src_id_data), &src_id_len))
1716       return FALSE;
1717   if (dst_id)
1718     if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1719                         sizeof(dst_id_data), &dst_id_len))
1720       return FALSE;
1721
1722   ret = silc_packet_send_raw(stream, type, flags,
1723                              src_id ? src_id_type : stream->src_id_type,
1724                              src_id ? src_id_data : stream->src_id,
1725                              src_id ? src_id_len : stream->src_id_len,
1726                              dst_id ? dst_id_type : stream->dst_id_type,
1727                              dst_id ? dst_id_data : stream->dst_id,
1728                              dst_id ? dst_id_len : stream->dst_id_len,
1729                              data, data_len,
1730                              cipher ? cipher : stream->send_key[0],
1731                              hmac ? hmac : stream->send_hmac[0]);
1732
1733   /* Write the packet to the stream */
1734   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1735 }
1736
1737 /* Sends packet after formatting the arguments to buffer */
1738
1739 SilcBool silc_packet_send_va(SilcPacketStream stream,
1740                              SilcPacketType type, SilcPacketFlags flags, ...)
1741 {
1742   SilcBufferStruct buf;
1743   SilcBool ret;
1744   va_list va;
1745
1746   va_start(va, flags);
1747
1748   memset(&buf, 0, sizeof(buf));
1749   if (silc_buffer_format_vp(&buf, va) < 0) {
1750     va_end(va);
1751     return FALSE;
1752   }
1753
1754   ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1755                          silc_buffer_len(&buf));
1756
1757   silc_buffer_purge(&buf);
1758   va_end(va);
1759
1760   return ret;
1761 }
1762
1763 /* Sends packet after formatting the arguments to buffer, extended routine */
1764
1765 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1766                                  SilcPacketType type, SilcPacketFlags flags,
1767                                  SilcIdType src_id_type, void *src_id,
1768                                  SilcIdType dst_id_type, void *dst_id,
1769                                  SilcCipher cipher, SilcHmac hmac, ...)
1770 {
1771   SilcBufferStruct buf;
1772   SilcBool ret;
1773   va_list va;
1774
1775   va_start(va, hmac);
1776
1777   memset(&buf, 0, sizeof(buf));
1778   if (silc_buffer_format_vp(&buf, va) < 0) {
1779     va_end(va);
1780     return FALSE;
1781   }
1782
1783   ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1784                              dst_id_type, dst_id, silc_buffer_data(&buf),
1785                              silc_buffer_len(&buf), cipher, hmac);
1786
1787   silc_buffer_purge(&buf);
1788   va_end(va);
1789
1790   return TRUE;
1791 }
1792
1793 /***************************** Packet Receiving *****************************/
1794
1795 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1796
1797 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1798                                              const unsigned char *data,
1799                                              SilcUInt32 data_len,
1800                                              const unsigned char *packet_mac,
1801                                              const unsigned char *packet_seq,
1802                                              SilcUInt32 sequence)
1803 {
1804   /* Check MAC */
1805   if (silc_likely(hmac)) {
1806     unsigned char mac[32], psn[4];
1807     SilcUInt32 mac_len;
1808
1809     SILC_LOG_DEBUG(("Verifying MAC"));
1810
1811     /* Compute HMAC of packet */
1812     silc_hmac_init(hmac);
1813
1814     if (!packet_seq) {
1815       SILC_PUT32_MSB(sequence, psn);
1816       silc_hmac_update(hmac, psn, 4);
1817     } else
1818       silc_hmac_update(hmac, packet_seq, 4);
1819
1820     silc_hmac_update(hmac, data, data_len);
1821     silc_hmac_final(hmac, mac, &mac_len);
1822
1823     /* Compare the MAC's */
1824     if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1825       SILC_LOG_DEBUG(("MAC failed"));
1826       return FALSE;
1827     }
1828
1829     SILC_LOG_DEBUG(("MAC is Ok"));
1830   }
1831
1832   return TRUE;
1833 }
1834
1835 /* Increments/sets counter when decrypting in counter mode. */
1836
1837 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1838                                                      unsigned char *iv,
1839                                                      unsigned char *packet_iv)
1840 {
1841   SilcUInt32 pc1, pc2;
1842
1843   /* If IV Included flag, set the IV from packet to block counter. */
1844   if (stream->iv_included) {
1845     memcpy(iv + 4, packet_iv, 8);
1846   } else {
1847     /* Increment 64-bit packet counter. */
1848     SILC_GET32_MSB(pc1, iv + 4);
1849     SILC_GET32_MSB(pc2, iv + 8);
1850     if (++pc2 == 0)
1851       ++pc1;
1852     SILC_PUT32_MSB(pc1, iv + 4);
1853     SILC_PUT32_MSB(pc2, iv + 8);
1854   }
1855
1856   /* Reset block counter */
1857   memset(iv + 12, 0, 4);
1858
1859   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1860 }
1861
1862 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
1863    Return 0 when packet is normal and 1 when it it special, -1 on error. */
1864
1865 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1866                                       SilcUInt32 sequence, SilcBuffer buffer,
1867                                       SilcBool normal)
1868 {
1869   if (normal == TRUE) {
1870     if (silc_likely(cipher)) {
1871       /* Decrypt rest of the packet */
1872       SILC_LOG_DEBUG(("Decrypting the packet"));
1873       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1874                                              buffer->data,
1875                                              silc_buffer_len(buffer), NULL)))
1876         return -1;
1877     }
1878     return 0;
1879
1880   } else {
1881     /* Decrypt rest of the header plus padding */
1882     if (silc_likely(cipher)) {
1883       SilcUInt16 len;
1884       SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1885
1886       SILC_LOG_DEBUG(("Decrypting the header"));
1887
1888       /* Padding length + src id len + dst id len + header length - 16
1889          bytes already decrypted, gives the rest of the encrypted packet */
1890       silc_buffer_push(buffer, block_len);
1891       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1892               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1893              block_len);
1894       silc_buffer_pull(buffer, block_len);
1895
1896       if (silc_unlikely(len > silc_buffer_len(buffer))) {
1897         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1898                         "packet dropped"));
1899         return -1;
1900       }
1901       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1902                                              buffer->data, len, NULL)))
1903         return -1;
1904     }
1905
1906     return 1;
1907   }
1908 }
1909
1910 /* Parses the packet. This is called when a whole packet is ready to be
1911    parsed. The buffer sent must be already decrypted before calling this
1912    function. */
1913
1914 static inline SilcBool silc_packet_parse(SilcPacket packet)
1915 {
1916   SilcBuffer buffer = &packet->buffer;
1917   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1918   SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1919   int ret;
1920
1921   SILC_LOG_DEBUG(("Parsing incoming packet"));
1922
1923   /* Parse the buffer.  This parses the SILC header of the packet. */
1924   ret = silc_buffer_unformat(buffer,
1925                              SILC_STR_ADVANCE,
1926                              SILC_STR_OFFSET(6),
1927                              SILC_STR_UI_CHAR(&src_id_len),
1928                              SILC_STR_UI_CHAR(&dst_id_len),
1929                              SILC_STR_UI_CHAR(&src_id_type),
1930                              SILC_STR_END);
1931   if (silc_unlikely(ret == -1)) {
1932     if (!packet->stream->udp &&
1933         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1934       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1935     return FALSE;
1936   }
1937
1938   if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1939                     dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1940     if (!packet->stream->udp &&
1941         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1942       SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1943                       packet->src_id_len, packet->dst_id_len));
1944     return FALSE;
1945   }
1946
1947   ret = silc_buffer_unformat(buffer,
1948                              SILC_STR_ADVANCE,
1949                              SILC_STR_DATA(&packet->src_id, src_id_len),
1950                              SILC_STR_UI_CHAR(&dst_id_type),
1951                              SILC_STR_DATA(&packet->dst_id, dst_id_len),
1952                              SILC_STR_OFFSET(padlen),
1953                              SILC_STR_END);
1954   if (silc_unlikely(ret == -1)) {
1955     if (!packet->stream->udp &&
1956         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1957       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1958     return FALSE;
1959   }
1960
1961   if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1962                     dst_id_type > SILC_ID_CHANNEL)) {
1963     if (!packet->stream->udp &&
1964         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1965       SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1966                       src_id_type, dst_id_type));
1967     return FALSE;
1968   }
1969
1970   packet->src_id_len = src_id_len;
1971   packet->dst_id_len = dst_id_len;
1972   packet->src_id_type = src_id_type;
1973   packet->dst_id_type = dst_id_type;
1974
1975   SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1976                    silc_buffer_len(buffer)), buffer->head,
1977                    silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1978
1979   SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
1980                   silc_get_packet_name(packet->type), packet->flags));
1981
1982   return TRUE;
1983 }
1984
1985 /* Dispatch packet to application.  Called with stream->lock locked.
1986    Returns FALSE if the stream was destroyed while dispatching a packet. */
1987
1988 static SilcBool silc_packet_dispatch(SilcPacket packet)
1989 {
1990   SilcPacketStream stream = packet->stream;
1991   SilcPacketProcess p;
1992   SilcBool default_sent = FALSE;
1993   SilcPacketType *pt;
1994
1995   /* Dispatch packet to all packet processors that want it */
1996
1997   if (silc_likely(!stream->process)) {
1998     /* Send to default processor as no others exist */
1999     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2000     silc_mutex_unlock(stream->lock);
2001     if (silc_unlikely(!stream->sc->engine->callbacks->
2002                       packet_receive(stream->sc->engine, stream, packet,
2003                                      stream->sc->engine->callback_context,
2004                                      stream->stream_context)))
2005       silc_packet_free(packet);
2006     silc_mutex_lock(stream->lock);
2007     return stream->destroyed == FALSE;
2008   }
2009
2010   silc_dlist_start(stream->process);
2011   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2012
2013     /* If priority is 0 or less, we send to default processor first
2014        because default processor has 0 priority */
2015     if (!default_sent && p->priority <= 0) {
2016       SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2017       default_sent = TRUE;
2018       silc_mutex_unlock(stream->lock);
2019       if (stream->sc->engine->callbacks->
2020           packet_receive(stream->sc->engine, stream, packet,
2021                          stream->sc->engine->callback_context,
2022                          stream->stream_context)) {
2023         silc_mutex_lock(stream->lock);
2024         return stream->destroyed == FALSE;
2025       }
2026       silc_mutex_lock(stream->lock);
2027     }
2028
2029     /* Send to processor */
2030     if (!p->types) {
2031       /* Send all packet types */
2032       SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2033       silc_mutex_unlock(stream->lock);
2034       if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2035                                        p->callback_context,
2036                                        stream->stream_context)) {
2037         silc_mutex_lock(stream->lock);
2038         return stream->destroyed == FALSE;
2039       }
2040       silc_mutex_lock(stream->lock);
2041     } else {
2042       /* Send specific types */
2043       for (pt = p->types; *pt; pt++) {
2044         if (*pt != packet->type)
2045           continue;
2046         SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2047         silc_mutex_unlock(stream->lock);
2048         if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2049                                          p->callback_context,
2050                                          stream->stream_context)) {
2051           silc_mutex_lock(stream->lock);
2052           return stream->destroyed == FALSE;
2053         }
2054         silc_mutex_lock(stream->lock);
2055         break;
2056       }
2057     }
2058   }
2059
2060   if (!default_sent) {
2061     /* Send to default processor as it has not been sent yet */
2062     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2063     silc_mutex_unlock(stream->lock);
2064     if (stream->sc->engine->callbacks->
2065         packet_receive(stream->sc->engine, stream, packet,
2066                        stream->sc->engine->callback_context,
2067                        stream->stream_context)) {
2068       silc_mutex_lock(stream->lock);
2069       return stream->destroyed == FALSE;
2070     }
2071     silc_mutex_lock(stream->lock);
2072   }
2073
2074   /* If we got here, no one wanted the packet, so drop it */
2075   silc_packet_free(packet);
2076   return stream->destroyed == FALSE;
2077 }
2078
2079 /* Process incoming data and parse packets.  Called with stream->lock
2080    locked. */
2081
2082 static void silc_packet_read_process(SilcPacketStream stream)
2083 {
2084   SilcBuffer inbuf;
2085   SilcCipher cipher;
2086   SilcHmac hmac;
2087   SilcPacket packet;
2088   SilcUInt8 sid;
2089   SilcUInt16 packetlen;
2090   SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2091   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2092   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2093   SilcBool normal;
2094   int ret;
2095
2096   /* Get inbuf.  If there is already some data for this stream in the buffer
2097      we already have it.  Otherwise get the current one from list, it will
2098      include the data. */
2099   inbuf = stream->inbuf;
2100   if (!inbuf) {
2101     silc_dlist_start(stream->sc->inbufs);
2102     inbuf = silc_dlist_get(stream->sc->inbufs);
2103   }
2104
2105   /* Parse the packets from the data */
2106   while (silc_buffer_len(inbuf) > 0) {
2107     ivlen = psnlen = 0;
2108     cipher = stream->receive_key[0];
2109     hmac = stream->receive_hmac[0];
2110     normal = FALSE;
2111
2112     if (silc_unlikely(silc_buffer_len(inbuf) <
2113                       (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2114                        SILC_PACKET_MIN_HEADER_LEN))) {
2115       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2116       silc_dlist_del(stream->sc->inbufs, inbuf);
2117       stream->inbuf = inbuf;
2118       return;
2119     }
2120
2121     if (silc_likely(hmac))
2122       mac_len = silc_hmac_len(hmac);
2123     else
2124       mac_len = 0;
2125
2126     /* Decrypt first block of the packet to get the length field out */
2127     if (silc_likely(cipher)) {
2128       block_len = silc_cipher_get_block_len(cipher);
2129
2130       if (stream->iv_included) {
2131         /* SID, IV and sequence number is included in the ciphertext */
2132         sid = (SilcUInt8)inbuf->data[0];
2133
2134         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2135           /* Set the CTR mode IV from packet to counter block */
2136           memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2137           silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2138           ivlen = 8 + 1;
2139         } else {
2140           /* Get IV from packet */
2141           memcpy(iv, inbuf->data + 1, block_len);
2142           ivlen = block_len + 1;
2143         }
2144         psnlen = 4;
2145
2146         /* Check SID, and get correct decryption key */
2147         if (sid != stream->sid) {
2148           /* If SID is recent get the previous key and use it */
2149           if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2150               stream->receive_key[1] && !stream->receive_hmac[1]) {
2151             cipher = stream->receive_key[1];
2152             hmac = stream->receive_hmac[1];
2153           } else {
2154             /* The SID is unknown, drop rest of the data in buffer */
2155             SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2156                             sid, stream->sid));
2157             silc_mutex_unlock(stream->lock);
2158             SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2159             silc_mutex_lock(stream->lock);
2160             goto out;
2161           }
2162         }
2163       } else {
2164         memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2165
2166         /* If using CTR mode, increment the counter */
2167         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2168           silc_packet_receive_ctr_increment(stream, iv, NULL);
2169       }
2170
2171       if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2172         silc_cipher_set_iv(cipher, NULL);
2173       silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2174
2175       header = tmp;
2176       if (stream->iv_included) {
2177         /* Take sequence number from packet */
2178         packet_seq = header;
2179         header += 4;
2180       }
2181     } else {
2182       /* Unencrypted packet */
2183       block_len = SILC_PACKET_MIN_HEADER_LEN;
2184       header = inbuf->data;
2185     }
2186
2187     /* Get packet length and full packet length with padding */
2188     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2189
2190     /* Sanity checks */
2191     if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2192       if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2193         SILC_LOG_ERROR(("Received too short packet"));
2194       silc_mutex_unlock(stream->lock);
2195       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2196       silc_mutex_lock(stream->lock);
2197       memset(tmp, 0, sizeof(tmp));
2198       goto out;
2199     }
2200
2201     if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2202       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2203                       "(%d bytes)",
2204                       paddedlen + mac_len - silc_buffer_len(inbuf)));
2205       memset(tmp, 0, sizeof(tmp));
2206       silc_dlist_del(stream->sc->inbufs, inbuf);
2207       stream->inbuf = inbuf;
2208       return;
2209     }
2210
2211     /* Check MAC of the packet */
2212     if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2213                                              paddedlen + ivlen,
2214                                              inbuf->data + ivlen +
2215                                              paddedlen, packet_seq,
2216                                              stream->receive_psn))) {
2217       silc_mutex_unlock(stream->lock);
2218       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2219       silc_mutex_lock(stream->lock);
2220       memset(tmp, 0, sizeof(tmp));
2221       goto out;
2222     }
2223
2224     /* Get packet */
2225     packet = silc_packet_alloc(stream->sc->engine);
2226     if (silc_unlikely(!packet)) {
2227       silc_mutex_unlock(stream->lock);
2228       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2229       silc_mutex_lock(stream->lock);
2230       memset(tmp, 0, sizeof(tmp));
2231       goto out;
2232     }
2233     packet->stream = stream;
2234
2235     /* Allocate more space to packet buffer, if needed */
2236     if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2237       if (!silc_buffer_realloc(&packet->buffer,
2238                                silc_buffer_truelen(&packet->buffer) +
2239                                (paddedlen -
2240                                 silc_buffer_truelen(&packet->buffer)))) {
2241         silc_mutex_unlock(stream->lock);
2242         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2243         silc_mutex_lock(stream->lock);
2244         silc_packet_free(packet);
2245         memset(tmp, 0, sizeof(tmp));
2246         goto out;
2247       }
2248     }
2249
2250     /* Parse packet header */
2251     packet->flags = (SilcPacketFlags)header[2];
2252     packet->type = (SilcPacketType)header[3];
2253
2254     if (stream->sc->engine->local_is_router) {
2255       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2256           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2257         normal = FALSE;
2258       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2259                (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2260                 stream->is_router == TRUE))
2261         normal = TRUE;
2262     } else {
2263       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2264           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2265         normal = FALSE;
2266       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2267         normal = TRUE;
2268     }
2269
2270     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2271                       stream->receive_psn, paddedlen + ivlen + mac_len),
2272                      inbuf->data, paddedlen + ivlen + mac_len);
2273
2274     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2275     silc_buffer_pull_tail(&packet->buffer, paddedlen);
2276     silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2277     silc_buffer_pull(&packet->buffer, block_len - psnlen);
2278     silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2279                                       psnlen + (block_len - psnlen)),
2280                     paddedlen - ivlen - psnlen - (block_len - psnlen));
2281     if (silc_likely(cipher)) {
2282       silc_cipher_set_iv(cipher, iv);
2283       ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2284                                 &packet->buffer, normal);
2285       if (silc_unlikely(ret < 0)) {
2286         silc_mutex_unlock(stream->lock);
2287         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2288         silc_mutex_lock(stream->lock);
2289         silc_packet_free(packet);
2290         memset(tmp, 0, sizeof(tmp));
2291         goto out;
2292       }
2293
2294       stream->receive_psn++;
2295     }
2296     silc_buffer_push(&packet->buffer, block_len);
2297
2298     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2299     silc_buffer_pull(inbuf, paddedlen + mac_len);
2300
2301     /* Parse the packet */
2302     if (silc_unlikely(!silc_packet_parse(packet))) {
2303       silc_mutex_unlock(stream->lock);
2304       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2305       silc_mutex_lock(stream->lock);
2306       silc_packet_free(packet);
2307       memset(tmp, 0, sizeof(tmp));
2308       goto out;
2309     }
2310
2311     /* Dispatch the packet to application */
2312     if (!silc_packet_dispatch(packet))
2313       break;
2314   }
2315
2316  out:
2317   /* Add inbuf back to free list, if we owned it. */
2318   if (stream->inbuf) {
2319     silc_dlist_add(stream->sc->inbufs, inbuf);
2320     stream->inbuf = NULL;
2321   }
2322
2323   silc_buffer_reset(inbuf);
2324 }
2325
2326 /****************************** Packet Waiting ******************************/
2327
2328 /* Packet wait receive callback */
2329 static SilcBool
2330 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2331                                 SilcPacketStream stream,
2332                                 SilcPacket packet,
2333                                 void *callback_context,
2334                                 void *stream_context);
2335
2336 /* Packet waiting callbacks */
2337 static SilcPacketCallbacks silc_packet_wait_cbs =
2338 {
2339   silc_packet_wait_packet_receive, NULL, NULL
2340 };
2341
2342 /* Packet waiting context */
2343 typedef struct {
2344   SilcMutex wait_lock;
2345   SilcCond wait_cond;
2346   SilcList packet_queue;
2347   unsigned char id[28];
2348   unsigned int id_type     : 2;
2349   unsigned int id_len      : 5;
2350   unsigned int stopped     : 1;
2351 } *SilcPacketWait;
2352
2353 /* Packet wait receive callback */
2354
2355 static SilcBool
2356 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2357                                 SilcPacketStream stream,
2358                                 SilcPacket packet,
2359                                 void *callback_context,
2360                                 void *stream_context)
2361 {
2362   SilcPacketWait pw = callback_context;
2363
2364   /* If source ID is specified check for it */
2365   if (pw->id_len) {
2366     if (pw->id_type != packet->src_id_type ||
2367         memcmp(pw->id, packet->src_id, pw->id_len))
2368       return FALSE;
2369   }
2370
2371   /* Signal the waiting thread for a new packet */
2372   silc_mutex_lock(pw->wait_lock);
2373
2374   if (silc_unlikely(pw->stopped)) {
2375     silc_mutex_unlock(pw->wait_lock);
2376     return FALSE;
2377   }
2378
2379   silc_list_add(pw->packet_queue, packet);
2380   silc_cond_broadcast(pw->wait_cond);
2381
2382   silc_mutex_unlock(pw->wait_lock);
2383
2384   return TRUE;
2385 }
2386
2387 /* Initialize packet waiting */
2388
2389 void *silc_packet_wait_init(SilcPacketStream stream,
2390                             const SilcID *source_id, ...)
2391 {
2392   SilcPacketWait pw;
2393   SilcBool ret;
2394   va_list ap;
2395
2396   pw = silc_calloc(1, sizeof(*pw));
2397   if (!pw)
2398     return NULL;
2399
2400   /* Allocate mutex and conditional variable */
2401   if (!silc_mutex_alloc(&pw->wait_lock)) {
2402     silc_free(pw);
2403     return NULL;
2404   }
2405   if (!silc_cond_alloc(&pw->wait_cond)) {
2406     silc_mutex_free(pw->wait_lock);
2407     silc_free(pw);
2408     return NULL;
2409   }
2410
2411   /* Link to the packet stream for the requested packet types */
2412   va_start(ap, source_id);
2413   ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2414                                    10000000, ap);
2415   va_end(ap);
2416   if (!ret) {
2417     silc_cond_free(pw->wait_cond);
2418     silc_mutex_free(pw->wait_lock);
2419     silc_free(pw);
2420     return NULL;
2421   }
2422
2423   /* Initialize packet queue */
2424   silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2425
2426   if (source_id) {
2427     SilcUInt32 id_len;
2428     silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2429                    sizeof(pw->id), &id_len);
2430     pw->id_type = source_id->type;
2431     pw->id_len = id_len;
2432   }
2433
2434   return (void *)pw;
2435 }
2436
2437 /* Uninitialize packet waiting */
2438
2439 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2440 {
2441   SilcPacketWait pw = waiter;
2442   SilcPacket packet;
2443
2444   /* Signal any threads to stop waiting */
2445   silc_mutex_lock(pw->wait_lock);
2446   pw->stopped = TRUE;
2447   silc_cond_broadcast(pw->wait_cond);
2448   silc_mutex_unlock(pw->wait_lock);
2449   silc_thread_yield();
2450
2451   /* Re-acquire lock and free resources */
2452   silc_mutex_lock(pw->wait_lock);
2453   silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2454
2455   /* Free any remaining packets */
2456   silc_list_start(pw->packet_queue);
2457   while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2458     silc_packet_free(packet);
2459
2460   silc_mutex_unlock(pw->wait_lock);
2461   silc_cond_free(pw->wait_cond);
2462   silc_mutex_free(pw->wait_lock);
2463   silc_free(pw);
2464 }
2465
2466 /* Blocks thread until a packet has been received. */
2467
2468 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2469 {
2470   SilcPacketWait pw = waiter;
2471   SilcBool ret = FALSE;
2472
2473   silc_mutex_lock(pw->wait_lock);
2474
2475   /* Wait here until packet has arrived */
2476   while (silc_list_count(pw->packet_queue) == 0) {
2477     if (silc_unlikely(pw->stopped)) {
2478       silc_mutex_unlock(pw->wait_lock);
2479       return -1;
2480     }
2481     ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2482   }
2483
2484   /* Return packet */
2485   silc_list_start(pw->packet_queue);
2486   *return_packet = silc_list_get(pw->packet_queue);
2487   silc_list_del(pw->packet_queue, *return_packet);
2488
2489   silc_mutex_unlock(pw->wait_lock);
2490
2491   return ret == TRUE ? 1 : 0;
2492 }
2493
2494 /************************** Packet Stream Wrapper ***************************/
2495
2496 /* Packet stream wrapper receive callback */
2497 static SilcBool
2498 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2499                                 SilcPacketStream stream,
2500                                 SilcPacket packet,
2501                                 void *callback_context,
2502                                 void *stream_context);
2503
2504 const SilcStreamOps silc_packet_stream_ops;
2505
2506 /* Packet stream wrapper context */
2507 typedef struct {
2508   const SilcStreamOps *ops;
2509   SilcPacketStream stream;
2510   SilcMutex lock;
2511   void *waiter;                   /* Waiter context in blocking mode */
2512   SilcPacketWrapCoder coder;
2513   void *coder_context;
2514   SilcBuffer encbuf;
2515   SilcStreamNotifier callback;
2516   void *context;
2517   SilcList in_queue;
2518   SilcPacketType type;
2519   SilcPacketFlags flags;
2520   unsigned int closed        : 1;
2521   unsigned int blocking      : 1;
2522   unsigned int read_more     : 1;
2523 } *SilcPacketWrapperStream;
2524
2525 /* Packet wrapper callbacks */
2526 static SilcPacketCallbacks silc_packet_wrap_cbs =
2527 {
2528   silc_packet_wrap_packet_receive, NULL, NULL
2529 };
2530
2531 /* Packet stream wrapper receive callback, non-blocking mode */
2532
2533 static SilcBool
2534 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2535                                 SilcPacketStream stream,
2536                                 SilcPacket packet,
2537                                 void *callback_context,
2538                                 void *stream_context)
2539 {
2540   SilcPacketWrapperStream pws = callback_context;
2541
2542   if (pws->closed || !pws->callback)
2543     return FALSE;
2544
2545   silc_mutex_lock(pws->lock);
2546   silc_list_add(pws->in_queue, packet);
2547   silc_mutex_unlock(pws->lock);
2548
2549   /* Call notifier callback */
2550   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2551
2552   return TRUE;
2553 }
2554
2555 /* Task callback to notify more data is available for reading */
2556
2557 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2558 {
2559   SilcPacketWrapperStream pws = context;
2560
2561   if (pws->closed || !pws->callback)
2562     return;
2563
2564   /* Call notifier callback */
2565   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2566 }
2567
2568 /* Read SILC packet */
2569
2570 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2571                           SilcUInt32 buf_len)
2572 {
2573   SilcPacketWrapperStream pws = stream;
2574   SilcPacket packet;
2575   SilcBool read_more = FALSE;
2576   int len;
2577
2578   if (pws->closed)
2579     return -2;
2580
2581   if (pws->blocking) {
2582     /* Block until packet is received */
2583     if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2584       return -2;
2585     if (pws->closed)
2586       return -2;
2587   } else {
2588     /* Non-blocking mode */
2589     silc_mutex_lock(pws->lock);
2590     if (!silc_list_count(pws->in_queue)) {
2591       silc_mutex_unlock(pws->lock);
2592       return -1;
2593     }
2594
2595     silc_list_start(pws->in_queue);
2596     packet = silc_list_get(pws->in_queue);
2597     silc_list_del(pws->in_queue, packet);
2598     silc_mutex_unlock(pws->lock);
2599   }
2600
2601   /* Call decoder if set */
2602   if (pws->coder && !pws->read_more)
2603     pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2604                pws->coder_context);
2605
2606   len = silc_buffer_len(&packet->buffer);
2607   if (len > buf_len) {
2608     len = buf_len;
2609     read_more = TRUE;
2610   }
2611
2612   /* Read data */
2613   memcpy(buf, packet->buffer.data, len);
2614
2615   if (read_more && !pws->blocking) {
2616     /* More data will be available (in blocking mode not supported). */
2617     silc_buffer_pull(&packet->buffer, len);
2618     silc_list_insert(pws->in_queue, NULL, packet);
2619     silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2620                                    silc_packet_wrap_read_more, pws, 0, 0);
2621     pws->read_more = TRUE;
2622     return len;
2623   }
2624
2625   pws->read_more = FALSE;
2626   silc_packet_free(packet);
2627   return len;
2628 }
2629
2630 /* Write SILC packet */
2631
2632 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2633                            SilcUInt32 data_len)
2634 {
2635   SilcPacketWrapperStream pws = stream;
2636   SilcBool ret = FALSE;
2637
2638   /* Call encoder if set */
2639   if (pws->coder) {
2640     silc_buffer_reset(pws->encbuf);
2641     ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2642                      pws->coder_context);
2643   }
2644
2645   /* Send the SILC packet */
2646   if (ret) {
2647     if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2648                              SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2649                                            silc_buffer_len(pws->encbuf)),
2650                              SILC_STR_DATA(data, data_len),
2651                              SILC_STR_END))
2652       return -2;
2653   } else {
2654     if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2655       return -2;
2656   }
2657
2658   return data_len;
2659 }
2660
2661 /* Close stream */
2662
2663 SilcBool silc_packet_wrap_close(SilcStream stream)
2664 {
2665   SilcPacketWrapperStream pws = stream;
2666
2667   if (pws->closed)
2668     return TRUE;
2669
2670   if (pws->blocking) {
2671     /* Close packet waiter */
2672     silc_packet_wait_uninit(pws->waiter, pws->stream);
2673   } else {
2674     /* Unlink */
2675     if (pws->callback)
2676       silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2677   }
2678   pws->closed = TRUE;
2679
2680   return TRUE;
2681 }
2682
2683 /* Destroy wrapper stream */
2684
2685 void silc_packet_wrap_destroy(SilcStream stream)
2686
2687 {
2688   SilcPacketWrapperStream pws = stream;
2689   SilcPacket packet;
2690
2691   SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2692
2693   silc_stream_close(stream);
2694   silc_list_start(pws->in_queue);
2695   while ((packet = silc_list_get(pws->in_queue)))
2696     silc_packet_free(packet);
2697   if (pws->lock)
2698     silc_mutex_free(pws->lock);
2699   if (pws->encbuf)
2700     silc_buffer_free(pws->encbuf);
2701   silc_packet_stream_unref(pws->stream);
2702
2703   silc_free(pws);
2704 }
2705
2706 /* Link stream to receive packets */
2707
2708 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2709                                    SilcSchedule schedule,
2710                                    SilcStreamNotifier callback,
2711                                    void *context)
2712 {
2713   SilcPacketWrapperStream pws = stream;
2714
2715   if (pws->closed || pws->blocking)
2716     return FALSE;
2717
2718   /* Link to receive packets */
2719   if (callback)
2720     silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2721                             100000, pws->type, -1);
2722   else
2723     silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2724
2725   pws->callback = callback;
2726   pws->context = context;
2727
2728   return TRUE;
2729 }
2730
2731 /* Return schedule */
2732
2733 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2734 {
2735   return NULL;
2736 }
2737
2738 /* Wraps packet stream into SilcStream. */
2739
2740 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2741                                    SilcPacketType type,
2742                                    SilcPacketFlags flags,
2743                                    SilcBool blocking_mode,
2744                                    SilcPacketWrapCoder coder,
2745                                    void *context)
2746 {
2747   SilcPacketWrapperStream pws;
2748
2749   pws = silc_calloc(1, sizeof(*pws));
2750   if (!pws)
2751     return NULL;
2752
2753   SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2754
2755   pws->ops = &silc_packet_stream_ops;
2756   pws->stream = stream;
2757   pws->type = type;
2758   pws->flags = flags;
2759   pws->blocking = blocking_mode;
2760   pws->coder = coder;
2761   pws->coder_context = context;
2762
2763   /* Allocate small amount for encoder buffer. */
2764   if (pws->coder)
2765     pws->encbuf = silc_buffer_alloc(8);
2766
2767   if (pws->blocking) {
2768     /* Blocking mode.  Use packet waiter to do the thing. */
2769     pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2770     if (!pws->waiter) {
2771       silc_free(pws);
2772       return NULL;
2773     }
2774   } else {
2775     /* Non-blocking mode */
2776     silc_mutex_alloc(&pws->lock);
2777     silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2778   }
2779
2780   silc_packet_stream_ref(stream);
2781
2782   return (SilcStream)pws;
2783 }
2784
2785 const SilcStreamOps silc_packet_stream_ops =
2786 {
2787   silc_packet_wrap_read,
2788   silc_packet_wrap_write,
2789   silc_packet_wrap_close,
2790   silc_packet_wrap_destroy,
2791   silc_packet_wrap_notifier,
2792   silc_packet_wrap_get_schedule,
2793 };