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