Protocol 1.2 integration continues.
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 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 "silcincludes.h"
25
26 /******************************************************************************
27
28                           Packet Sending Routines
29
30 ******************************************************************************/
31
32 /* Actually sends the packet. This flushes the connections outgoing data
33    buffer. If data is sent directly to the network this returns the bytes
34    written, if error occured this returns -1 and if the data could not
35    be written directly to the network at this time this returns -2, in
36    which case the data should be queued by the caller and sent at some
37    later time. If `force_send' is TRUE this attempts to write the data
38    directly to the network, if FALSE, this returns -2. */
39
40 int silc_packet_send(SilcSocketConnection sock, bool force_send)
41 {
42   SILC_LOG_DEBUG(("Sending packet to %s:%d [%s]", sock->hostname,
43                   sock->port,  
44                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
45                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
46                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
47                    "Router")));
48
49   /* Send now if forced to do so */
50   if (force_send == TRUE) {
51     int ret;
52
53     SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
54
55     /* Write to network */
56     ret = silc_socket_write(sock);
57
58     if (ret == -1) {
59       SILC_LOG_ERROR(("Error sending packet, dropped: %s", 
60                       strerror(errno)));
61     }
62     if (ret != -2)
63       return ret;
64
65     SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
66   }  
67
68   SILC_LOG_DEBUG(("Packet in queue"));
69
70   return -2;
71 }
72
73 /* Encrypts a packet. This also creates HMAC of the packet before 
74    encryption and adds the HMAC at the end of the buffer. This assumes
75    that there is enough free space at the end of the buffer to add the
76    computed HMAC. This is the normal way of encrypting packets, if some
77    other process of HMAC computing and encryption is needed this function
78    cannot be used. */
79
80 void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, SilcUInt32 sequence,
81                          SilcBuffer buffer, SilcUInt32 len)
82 {
83
84   /* Encrypt the data area of the packet. */
85   if (cipher) {
86     SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d", 
87                     silc_cipher_get_name(cipher), len));
88     silc_cipher_encrypt(cipher, buffer->data, buffer->data, len,
89                         silc_cipher_get_iv(cipher));
90   }
91
92   /* Compute HMAC. This assumes that MAC is computed from the entire
93      data area thus this uses the length found in buffer, not the length
94      sent as argument. */
95   if (hmac) {
96     unsigned char mac[32], psn[4];
97     SilcUInt32 mac_len;
98
99     silc_hmac_init(hmac);
100     SILC_PUT32_MSB(sequence, psn);
101     silc_hmac_update(hmac, psn, 4);
102     silc_hmac_update(hmac, buffer->data, buffer->len);
103     silc_hmac_final(hmac, mac, &mac_len);
104
105     /* Put MAC and pull the it into the visible data area in the buffer */
106     silc_buffer_put_tail(buffer, mac, mac_len);
107     silc_buffer_pull_tail(buffer, mac_len);
108   }
109 }
110
111 /* Assembles a new packet to be ready for send out. */
112
113 bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng,
114                           SilcCipher cipher, SilcHmac hmac,
115                           SilcSocketConnection sock,
116                           const unsigned char *data, SilcUInt32 data_len,
117                           const SilcBuffer assembled_packet)
118
119   unsigned char tmppad[SILC_PACKET_MAX_PADLEN];   
120   int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
121   int i, ret;
122
123   SILC_LOG_DEBUG(("Assembling outgoing packet"));
124
125   /* Calculate the packet's length and padding length if upper layer
126      didn't already do it. */
127
128   /* Get the true length of the packet. This is saved as payload length
129      into the packet header. This does not include the length of the
130      padding. */
131   if (!packet->truelen) {
132     data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
133                                    packet->src_id_len + packet->dst_id_len);
134     packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
135       packet->src_id_len + packet->dst_id_len;
136   }
137
138   /* Calculate the length of the padding. The padding is calculated from
139      the data that will be encrypted. */
140   if (!packet->padlen) {
141     if (packet->long_pad)
142       SILC_PACKET_PADLEN_MAX(packet->truelen, block_len, packet->padlen);
143     else
144       SILC_PACKET_PADLEN(packet->truelen, block_len, packet->padlen);
145   }
146
147   /* Now prepare the outgoing data buffer for packet sending and start
148      assembling the packet. */
149
150   /* Return pointer to the assembled packet */
151   if (!silc_packet_send_prepare(sock, packet->truelen - data_len,
152                                 packet->padlen, data_len, hmac,
153                                 assembled_packet))
154     return FALSE;
155
156   /* Get random padding */
157   if (rng)
158     for (i = 0; i < packet->padlen; i++) tmppad[i] =
159                                            silc_rng_get_byte_fast(rng);
160   else
161     for (i = 0; i < packet->padlen; i++) tmppad[i] =
162                                            silc_rng_global_get_byte_fast();
163
164   /* Create the packet. This creates the SILC header, adds padding, and
165      the actual packet data. */
166   ret =
167     silc_buffer_format(assembled_packet,
168                        SILC_STR_UI_SHORT(packet->truelen),
169                        SILC_STR_UI_CHAR(packet->flags),
170                        SILC_STR_UI_CHAR(packet->type),
171                        SILC_STR_UI_CHAR(packet->padlen),
172                        SILC_STR_UI_CHAR(0),
173                        SILC_STR_UI_CHAR(packet->src_id_len),
174                        SILC_STR_UI_CHAR(packet->dst_id_len),
175                        SILC_STR_UI_CHAR(packet->src_id_type),
176                        SILC_STR_UI_XNSTRING(packet->src_id,
177                                             packet->src_id_len),
178                        SILC_STR_UI_CHAR(packet->dst_id_type),
179                        SILC_STR_UI_XNSTRING(packet->dst_id,
180                                             packet->dst_id_len),
181                        SILC_STR_UI_XNSTRING(tmppad, packet->padlen),
182                        SILC_STR_UI_XNSTRING(data, data_len),
183                        SILC_STR_END);
184   if (ret < 0)
185     return FALSE;
186
187   SILC_LOG_HEXDUMP(("Assembled packet, len %d", assembled_packet->len),
188                    assembled_packet->data, assembled_packet->len);
189
190   return TRUE;
191 }
192
193 /* Prepare outgoing data buffer for packet sending. This moves the data
194    area so that new packet may be added into it. If needed this allocates
195    more space to the buffer. This handles directly the connection's
196    outgoing buffer in SilcSocketConnection object, and returns the
197    pointer to that buffer into the `packet'. */
198
199 bool silc_packet_send_prepare(SilcSocketConnection sock,
200                               SilcUInt32 header_len,
201                               SilcUInt32 pad_len,
202                               SilcUInt32 data_len,
203                               SilcHmac hmac,
204                               const SilcBuffer packet)
205
206   int totlen;
207   unsigned char *oldptr;
208   int mac_len = hmac ? silc_hmac_len(hmac) : 0;
209
210   if (!packet)
211     return FALSE;
212
213   totlen = header_len + pad_len + data_len;
214
215   /* Prepare the outgoing buffer for packet sending. */
216   if (!sock->outbuf) {
217     /* Allocate new buffer. This is done only once per connection. */
218     SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
219
220     sock->outbuf = silc_buffer_alloc(totlen > SILC_PACKET_DEFAULT_SIZE ?
221                                      totlen : SILC_PACKET_DEFAULT_SIZE);
222     if (!sock->outbuf)
223       return FALSE;
224   } else {
225     if (!SILC_IS_OUTBUF_PENDING(sock)) {
226       /* Buffer is free for use */
227       silc_buffer_clear(sock->outbuf);
228     }
229   }
230
231   /* Allocate more space if needed */
232   if ((sock->outbuf->end - sock->outbuf->tail) < (totlen + mac_len)) {
233     SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
234     sock->outbuf = silc_buffer_realloc(sock->outbuf,
235                                        sock->outbuf->truelen + (totlen * 2));
236     if (!sock->outbuf)
237       return FALSE;
238   }
239
240   /* Pull data area for the new packet, and return pointer to the start of
241      the data area and save the pointer in to the `packet'. */
242   oldptr = silc_buffer_pull_tail(sock->outbuf, totlen + mac_len);
243   silc_buffer_set(packet, oldptr, totlen + mac_len);
244   silc_buffer_push_tail(packet, mac_len);
245
246   return TRUE;
247 }
248
249 /******************************************************************************
250
251                          Packet Reception Routines
252
253 ******************************************************************************/
254
255 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, 
256                                SilcUInt32 sequence, SilcBuffer buffer, 
257                                bool normal);
258 static bool silc_packet_check_mac(SilcHmac hmac,
259                                   const unsigned char *data,
260                                   SilcUInt32 data_len,
261                                   const unsigned char *packet_mac,
262                                   SilcUInt32 sequence);
263
264 /* Receives packet from network and reads the data into connection's
265    incoming data buffer. If the data was read directly this returns the
266    read bytes, if error occured this returns -1, if the data could not
267    be read directly at this time this returns -2 in which case the data
268    should be read again at some later time, or If EOF occured this returns
269    0. */
270
271 int silc_packet_receive(SilcSocketConnection sock)
272 {
273   int ret;
274
275   SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
276                   sock->port, 
277                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
278                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
279                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
280                    "Router")));
281
282   /* Read some data from connection */
283   ret = silc_socket_read(sock);
284
285   return ret;
286 }
287
288 /* Processes and decrypts the incmoing data, and calls parser callback
289    for each received packet that will handle the actual packet parsing.
290    If more than one packet was received this calls the parser multiple
291    times.  The parser callback will get context SilcPacketParserContext
292    that includes the packet and the `parser_context' sent to this
293    function. 
294    
295    The `local_is_router' indicates whether the caller is router server
296    in which case the receiving process of a certain packet types may
297    be special.  Normal server and client must set it to FALSE.  The
298    SilcPacketParserContext will indicate also whether the received
299    packet was normal or special packet. */
300
301 bool silc_packet_receive_process(SilcSocketConnection sock,
302                                  bool local_is_router,
303                                  SilcCipher cipher, SilcHmac hmac,
304                                  SilcUInt32 sequence,
305                                  SilcPacketParserCallback parser,
306                                  void *parser_context)
307 {
308   SilcPacketParserContext *parse_ctx;
309   int packetlen, paddedlen, mac_len = 0, ret, block_len;
310   bool cont = TRUE;
311   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
312   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
313
314   /* Do not process for disconnected connection */
315   if (SILC_IS_DISCONNECTED(sock))
316     return TRUE;
317
318   if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
319     return TRUE;
320
321   if (hmac)
322     mac_len = silc_hmac_len(hmac);
323
324   /* Parse the packets from the data */
325   while (sock->inbuf->len > 0 && cont) {
326
327     if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) {
328       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
329       return TRUE;
330     }
331
332     /* Decrypt first block of the packet to get the length field out */
333     if (cipher) {
334       block_len = silc_cipher_get_block_len(cipher);
335       memcpy(iv, silc_cipher_get_iv(cipher), block_len);
336       silc_cipher_decrypt(cipher, sock->inbuf->data, tmp, block_len, iv);
337       header = tmp;
338     } else {
339       block_len = SILC_PACKET_MIN_HEADER_LEN;
340       header = sock->inbuf->data;
341     }
342
343     /* Get packet lenght and full packet length with padding */
344     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
345
346     /* Sanity checks */
347     if (packetlen < SILC_PACKET_MIN_LEN) {
348       SILC_LOG_ERROR(("Received too short packet"));
349       memset(header, 0, sizeof(header));
350       silc_buffer_clear(sock->inbuf);
351       return FALSE;
352     }
353
354     if (sock->inbuf->len < paddedlen + mac_len) {
355       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
356                       "(%d bytes)", paddedlen + mac_len - sock->inbuf->len));
357       SILC_SET_INBUF_PENDING(sock);
358       memset(tmp, 0, sizeof(tmp));
359       return TRUE;
360     }
361
362     /* Check MAC of the packet */
363     if (!silc_packet_check_mac(hmac, sock->inbuf->data, paddedlen,
364                                sock->inbuf->data + paddedlen, sequence)) {
365       SILC_LOG_WARNING(("Packet MAC check failed %s:%d [%s] [%s]", 
366                         sock->hostname, sock->port,
367                         silc_get_packet_name(header[3]),
368                         (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
369                          sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
370                          sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
371                          "Router")));
372       memset(tmp, 0, sizeof(tmp));
373       silc_buffer_clear(sock->inbuf);
374       return FALSE;
375     }
376
377     SILC_UNSET_INBUF_PENDING(sock);
378     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
379     if (!parse_ctx)
380       return FALSE;
381     parse_ctx->packet = silc_packet_context_alloc();
382     parse_ctx->packet->buffer = silc_buffer_alloc_size(paddedlen);
383     parse_ctx->packet->type = header[3];
384     parse_ctx->packet->padlen = header[4];
385     parse_ctx->packet->sequence = sequence++;
386     parse_ctx->sock = sock;
387     parse_ctx->context = parser_context;
388
389     /* Check whether this is normal or special packet */
390     if (local_is_router) {
391       if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
392           (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
393         parse_ctx->normal = FALSE;
394       else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE || 
395                (header[3] == SILC_PACKET_CHANNEL_MESSAGE &&
396                 sock->type == SILC_SOCKET_TYPE_ROUTER))
397         parse_ctx->normal = TRUE;
398     } else {
399       if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
400           (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
401         parse_ctx->normal = FALSE;
402       else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE)
403         parse_ctx->normal = TRUE;
404     }
405
406     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
407                       sequence - 1, paddedlen + mac_len),
408                      sock->inbuf->data, paddedlen + mac_len);
409
410     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
411     silc_buffer_put(parse_ctx->packet->buffer, header, block_len);
412     silc_buffer_pull(parse_ctx->packet->buffer, block_len);
413     silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data + block_len,
414                     paddedlen - block_len);
415     if (cipher) {
416       silc_cipher_set_iv(cipher, iv);
417       ret = silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, 
418                                 parse_ctx->packet->buffer, 
419                                 parse_ctx->normal);
420       if (ret < 0) {
421         SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s] [%s]", 
422                           sock->hostname, sock->port,
423                           silc_get_packet_name(parse_ctx->packet->type),
424                           (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
425                            sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
426                            sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
427                            "Router")));
428         memset(tmp, 0, sizeof(tmp));
429         silc_packet_context_free(parse_ctx->packet);
430         silc_free(parse_ctx);
431         return FALSE;
432       }
433     }
434     silc_buffer_push(parse_ctx->packet->buffer, block_len);
435
436     SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d",
437                       parse_ctx->packet->buffer->len), 
438                      parse_ctx->packet->buffer->data,
439                      parse_ctx->packet->buffer->len);
440
441     /* Pull the packet from inbuf thus we'll get the next one
442        in the inbuf. */
443     silc_buffer_pull(sock->inbuf, paddedlen + mac_len);
444
445     /* Call the parser */
446     cont = (*parser)(parse_ctx, parser_context);
447     memset(tmp, 0, sizeof(tmp));
448   }
449
450   if (cont == FALSE && sock->inbuf->len > 0)
451     return TRUE;
452
453   SILC_LOG_DEBUG(("Clearing inbound buffer"));
454   silc_buffer_clear(sock->inbuf);
455   return TRUE;
456 }
457
458 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
459
460 static bool silc_packet_check_mac(SilcHmac hmac,
461                                   const unsigned char *data,
462                                   SilcUInt32 data_len,
463                                   const unsigned char *packet_mac,
464                                   SilcUInt32 sequence)
465 {
466   /* Check MAC */
467   if (hmac) {
468     unsigned char mac[32], psn[4];
469     SilcUInt32 mac_len;
470     
471     SILC_LOG_DEBUG(("Verifying MAC"));
472
473     /* Compute HMAC of packet */
474     silc_hmac_init(hmac);
475     SILC_PUT32_MSB(sequence, psn);
476     silc_hmac_update(hmac, psn, 4);
477     silc_hmac_update(hmac, data, data_len);
478     silc_hmac_final(hmac, mac, &mac_len);
479
480     /* Compare the MAC's */
481     if (memcmp(packet_mac, mac, mac_len)) {
482       SILC_LOG_ERROR(("MAC failed"));
483       return FALSE;
484     }
485     
486     SILC_LOG_DEBUG(("MAC is Ok"));
487   }
488   
489   return TRUE;
490 }
491
492 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
493    Return 0 when packet is normal and 1 when it it special, -1 on error. */
494
495 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
496                                SilcUInt32 sequence, SilcBuffer buffer, 
497                                bool normal)
498 {
499   /* If the packet type is not any special type lets decrypt rest
500      of the packet here. */
501   if (normal == TRUE) {
502     if (cipher) {
503       /* Decrypt rest of the packet */
504       SILC_LOG_DEBUG(("Decrypting the packet"));
505       silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len, 
506                           silc_cipher_get_iv(cipher));
507     }
508     return 0;
509
510   } else {
511     /* Decrypt rest of the header plus padding */
512     if (cipher) {
513       SilcUInt16 len;
514       int block_len = silc_cipher_get_block_len(cipher);
515
516       SILC_LOG_DEBUG(("Decrypting the header"));
517
518       /* padding length + src id len + dst id len + header length - 16
519          bytes already decrypted, gives the rest of the encrypted packet */
520       silc_buffer_push(buffer, block_len);
521       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] + 
522               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
523              block_len);
524
525       if (len > buffer->len) {
526         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
527                         "packet dropped"));
528         return -1;
529       }
530       silc_buffer_pull(buffer, block_len);
531       silc_cipher_decrypt(cipher, buffer->data, buffer->data, len,
532                           silc_cipher_get_iv(cipher));
533     }
534
535     return 1;
536   }
537 }
538
539 /* Parses the packet. This is called when a whole packet is ready to be
540    parsed. The buffer sent must be already decrypted before calling this 
541    function. The len argument must be the true length of the packet. This 
542    function returns the type of the packet. The data section of the 
543    buffer is parsed, not head or tail sections. */
544
545 SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
546 {
547   SilcBuffer buffer = ctx->buffer;
548   SilcUInt8 tmp;
549   int len, ret;
550   SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
551
552   SILC_LOG_DEBUG(("Parsing incoming packet"));
553
554   /* Check the length of the buffer */
555   if (buffer->len < SILC_PACKET_MIN_LEN) {
556     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
557     return SILC_PACKET_NONE;
558   }
559
560   /* Parse the buffer. This parses the SILC header of the packet. */
561   len = silc_buffer_unformat(buffer, 
562                              SILC_STR_UI_SHORT(&ctx->truelen),
563                              SILC_STR_UI_CHAR(&ctx->flags),
564                              SILC_STR_UI_CHAR(&ctx->type),
565                              SILC_STR_UI_CHAR(&padlen),
566                              SILC_STR_UI_CHAR(&tmp),
567                              SILC_STR_UI_CHAR(&src_id_len),
568                              SILC_STR_UI_CHAR(&dst_id_len),
569                              SILC_STR_UI_CHAR(&src_id_type),
570                              SILC_STR_END);
571   if (len == -1 || tmp != 0)
572     return SILC_PACKET_NONE;
573
574   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
575       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
576     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
577                     src_id_len, dst_id_len));
578     return SILC_PACKET_NONE;
579   }
580
581   silc_buffer_pull(buffer, len);
582   ret = silc_buffer_unformat(buffer, 
583                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
584                                                         src_id_len),
585                              SILC_STR_UI_CHAR(&dst_id_type),
586                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
587                                                         dst_id_len),
588                              SILC_STR_UI_XNSTRING(NULL, padlen),
589                              SILC_STR_END);
590   if (ret == -1)
591     return SILC_PACKET_NONE;
592
593   if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
594     SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
595                    src_id_type, dst_id_type));
596     return SILC_PACKET_NONE;
597   }
598
599   ctx->src_id_len = src_id_len;
600   ctx->dst_id_len = dst_id_len;
601   ctx->src_id_type = src_id_type;
602   ctx->dst_id_type = dst_id_type;
603   ctx->padlen = padlen;
604
605   silc_buffer_push(buffer, len);
606
607   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
608                    ctx->buffer->data, ctx->buffer->len);
609
610   /* Pull SILC header and padding from packet */
611   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
612                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
613
614   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
615
616   return ctx->type;
617 }
618
619 /* Perform special SILC Packet header parsing. This is required to some
620    packet types that have the data payload encrypted with different key
621    than the header area plus padding of the packet. Hence, this parses
622    the header in a way that it does not take the data area into account
623    and parses the header and padding area only. */
624
625 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
626                                          SilcCipher cipher)
627 {
628   SilcBuffer buffer = ctx->buffer;
629   SilcUInt8 tmp;
630   int len, ret;
631   SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
632
633   SILC_LOG_DEBUG(("Parsing incoming packet"));
634
635   /* Check the length of the buffer */
636   if (buffer->len < SILC_PACKET_MIN_LEN) {
637     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
638     return SILC_PACKET_NONE;
639   }
640
641   /* Parse the buffer. This parses the SILC header of the packet. */
642   len = silc_buffer_unformat(buffer, 
643                              SILC_STR_UI_SHORT(&ctx->truelen),
644                              SILC_STR_UI_CHAR(&ctx->flags),
645                              SILC_STR_UI_CHAR(&ctx->type),
646                              SILC_STR_UI_CHAR(&padlen),
647                              SILC_STR_UI_CHAR(&tmp),
648                              SILC_STR_UI_CHAR(&src_id_len),
649                              SILC_STR_UI_CHAR(&dst_id_len),
650                              SILC_STR_UI_CHAR(&src_id_type),
651                              SILC_STR_END);
652   if (len == -1 || tmp != 0) {
653     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
654     return SILC_PACKET_NONE;
655   }
656
657   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
658       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
659     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
660                     src_id_len, dst_id_len));
661     return SILC_PACKET_NONE;
662   }
663
664   silc_buffer_pull(buffer, len);
665   ret = silc_buffer_unformat(buffer, 
666                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
667                                                         src_id_len),
668                              SILC_STR_UI_CHAR(&dst_id_type),
669                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
670                                                         dst_id_len),
671                              SILC_STR_UI_XNSTRING(NULL, padlen),
672                              SILC_STR_END);
673   if (ret == -1) {
674     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
675     return SILC_PACKET_NONE;
676   }
677
678   if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
679     SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
680                    src_id_type, dst_id_type));
681     return SILC_PACKET_NONE;
682   }
683
684   ctx->src_id_len = src_id_len;
685   ctx->dst_id_len = dst_id_len;
686   ctx->src_id_type = src_id_type;
687   ctx->dst_id_type = dst_id_type;
688   ctx->padlen = padlen;
689
690   silc_buffer_push(buffer, len);
691
692   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
693                    ctx->buffer->data, ctx->buffer->len);
694
695   /* Pull SILC header and padding from packet */
696   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
697                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
698
699   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
700
701   return ctx->type;
702 }
703
704 /* Allocate packet context */
705
706 SilcPacketContext *silc_packet_context_alloc(void)
707 {
708   SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
709   if (!ctx)
710     return NULL;
711   ctx->users++;
712   return ctx;
713 }
714
715 /* Increse the reference count of the packet context. */
716
717 SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
718 {
719   ctx->users++;
720   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users - 1,
721                   ctx->users));
722   return ctx;
723 }
724
725 /* Decrese the reference count of the packet context and free it only if
726    it is zero. */
727
728 void silc_packet_context_free(SilcPacketContext *ctx)
729 {
730   ctx->users--;
731   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users + 1,
732                   ctx->users));
733   if (ctx->users < 1)
734     {
735       if (ctx->buffer)
736         silc_buffer_free(ctx->buffer);
737       if (ctx->src_id)
738         silc_free(ctx->src_id);
739       if (ctx->dst_id)
740         silc_free(ctx->dst_id);
741       silc_free(ctx);
742     }
743 }