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