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