Merged silc_1_0_branch to trunk.
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2005 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 to %s:%d [%s], dropped: %s",
60                       sock->hostname ? sock->hostname : "", sock->port,
61                       (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
62                        sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
63                        sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
64                        "Router"), strerror(errno)));
65     }
66     if (ret != -2)
67       return ret;
68
69     SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
70   }
71
72   SILC_LOG_DEBUG(("Packet in queue"));
73
74   return -2;
75 }
76
77 /* Encrypts a packet. This also creates HMAC of the packet before
78    encryption and adds the HMAC at the end of the buffer. This assumes
79    that there is enough free space at the end of the buffer to add the
80    computed HMAC. This is the normal way of encrypting packets, if some
81    other process of HMAC computing and encryption is needed this function
82    cannot be used. */
83
84 void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, SilcUInt32 sequence,
85                          SilcBuffer buffer, SilcUInt32 len)
86 {
87
88   /* Encrypt the data area of the packet. */
89   if (cipher) {
90     SILC_LOG_DEBUG(("Encrypting packet (%d), cipher %s, len %d",
91                     sequence, silc_cipher_get_name(cipher), len));
92     silc_cipher_encrypt(cipher, buffer->data, buffer->data, len, NULL);
93   }
94
95   /* Compute HMAC. This assumes that MAC is computed from the entire
96      data area thus this uses the length found in buffer, not the length
97      sent as argument. */
98   if (hmac) {
99     unsigned char mac[32], psn[4];
100     SilcUInt32 mac_len;
101
102     silc_hmac_init(hmac);
103     SILC_PUT32_MSB(sequence, psn);
104     silc_hmac_update(hmac, psn, 4);
105     silc_hmac_update(hmac, buffer->data, buffer->len);
106     silc_hmac_final(hmac, mac, &mac_len);
107
108     /* Put MAC and pull the it into the visible data area in the buffer */
109     silc_buffer_put_tail(buffer, mac, mac_len);
110     silc_buffer_pull_tail(buffer, mac_len);
111   }
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   unsigned 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   SilcUInt32 totlen;
210   unsigned char *oldptr;
211   unsigned 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 static bool silc_packet_check_mac(SilcHmac hmac,
262                                   const unsigned char *data,
263                                   SilcUInt32 data_len,
264                                   const unsigned char *packet_mac,
265                                   SilcUInt32 sequence);
266
267 /* Receives packet from network and reads the data into connection's
268    incoming data buffer. If the data was read directly this returns the
269    read bytes, if error occured this returns -1, if the data could not
270    be read directly at this time this returns -2 in which case the data
271    should be read again at some later time, or If EOF occured this returns
272    0. */
273
274 int silc_packet_receive(SilcSocketConnection sock)
275 {
276   int ret;
277
278   SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
279                   sock->port,
280                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
281                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
282                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
283                    "Router")));
284
285   /* Read some data from connection */
286   ret = silc_socket_read(sock);
287
288   return ret;
289 }
290
291 /* Processes and decrypts the incmoing data, and calls parser callback
292    for each received packet that will handle the actual packet parsing.
293    If more than one packet was received this calls the parser multiple
294    times.  The parser callback will get context SilcPacketParserContext
295    that includes the packet and the `parser_context' sent to this
296    function.
297
298    The `local_is_router' indicates whether the caller is router server
299    in which case the receiving process of a certain packet types may
300    be special.  Normal server and client must set it to FALSE.  The
301    SilcPacketParserContext will indicate also whether the received
302    packet was normal or special packet. */
303
304 bool silc_packet_receive_process(SilcSocketConnection sock,
305                                  bool local_is_router,
306                                  SilcCipher cipher, SilcHmac hmac,
307                                  SilcUInt32 sequence,
308                                  SilcPacketParserCallback parser,
309                                  void *parser_context)
310 {
311   SilcPacketParserContext *parse_ctx;
312   SilcUInt16 packetlen;
313   SilcUInt32 paddedlen, mac_len = 0, block_len;
314   int ret;
315   bool cont = TRUE;
316   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
317   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
318
319   /* Do not process for disconnected connection */
320   if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
321     return TRUE;
322
323   if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
324     return TRUE;
325
326   if (hmac)
327     mac_len = silc_hmac_len(hmac);
328
329   /* Parse the packets from the data */
330   silc_socket_dup(sock);
331   while (sock->inbuf->len > 0 && cont) {
332
333     if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) {
334       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
335       silc_socket_free(sock);
336       return TRUE;
337     }
338
339     /* Decrypt first block of the packet to get the length field out */
340     if (cipher) {
341       block_len = silc_cipher_get_block_len(cipher);
342       memcpy(iv, silc_cipher_get_iv(cipher), block_len);
343       silc_cipher_decrypt(cipher, sock->inbuf->data, tmp, block_len, iv);
344       header = tmp;
345     } else {
346       block_len = SILC_PACKET_MIN_HEADER_LEN;
347       header = sock->inbuf->data;
348     }
349
350     /* Get packet lenght and full packet length with padding */
351     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
352
353     /* Sanity checks */
354     if (packetlen < SILC_PACKET_MIN_LEN) {
355       SILC_LOG_ERROR(("Received too short packet"));
356       memset(header, 0, sizeof(header));
357       silc_buffer_clear(sock->inbuf);
358       silc_socket_free(sock);
359       return FALSE;
360     }
361
362     if (sock->inbuf->len < paddedlen + mac_len) {
363       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
364                       "(%d bytes)", paddedlen + mac_len - sock->inbuf->len));
365       SILC_SET_INBUF_PENDING(sock);
366       memset(tmp, 0, sizeof(tmp));
367       silc_socket_free(sock);
368       return TRUE;
369     }
370
371     /* Check MAC of the packet */
372     if (!silc_packet_check_mac(hmac, sock->inbuf->data, paddedlen,
373                                sock->inbuf->data + paddedlen, sequence)) {
374       SILC_LOG_WARNING(("Packet MAC check failed %s:%d "
375                         "[%s type %d len %dB blen %dB seq %d] [%s] proto %d",
376                         sock->hostname, sock->port,
377                         silc_get_packet_name(header[3]),
378                         header[3], paddedlen, sock->inbuf->len, sequence,
379                         (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
380                          sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
381                          sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
382                          "Router"),
383                         sock->protocol ? sock->protocol->protocol->type : -1));
384       memset(tmp, 0, sizeof(tmp));
385       silc_buffer_clear(sock->inbuf);
386       silc_socket_free(sock);
387       return FALSE;
388     }
389
390     SILC_UNSET_INBUF_PENDING(sock);
391     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
392     if (!parse_ctx) {
393       silc_socket_free(sock);
394       return FALSE;
395     }
396     parse_ctx->packet = silc_packet_context_alloc();
397     parse_ctx->packet->buffer = silc_buffer_alloc_size(paddedlen);
398     parse_ctx->packet->type = (SilcPacketType)header[3];
399     parse_ctx->packet->padlen = (SilcUInt8)header[4];
400     parse_ctx->packet->sequence = sequence++;
401     parse_ctx->sock = sock;
402     parse_ctx->context = parser_context;
403
404     /* Check whether this is normal or special packet */
405     if (local_is_router) {
406       if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
407           (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
408         parse_ctx->normal = FALSE;
409       else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE ||
410                (header[3] == SILC_PACKET_CHANNEL_MESSAGE &&
411                 sock->type == SILC_SOCKET_TYPE_ROUTER))
412         parse_ctx->normal = TRUE;
413     } else {
414       if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
415           (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
416         parse_ctx->normal = FALSE;
417       else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE)
418         parse_ctx->normal = TRUE;
419     }
420
421     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
422                       sequence - 1, paddedlen + mac_len),
423                      sock->inbuf->data, paddedlen + mac_len);
424
425     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
426     silc_buffer_put(parse_ctx->packet->buffer, header, block_len);
427     silc_buffer_pull(parse_ctx->packet->buffer, block_len);
428     silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data + block_len,
429                     paddedlen - block_len);
430     if (cipher) {
431       silc_cipher_set_iv(cipher, iv);
432       ret = silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence,
433                                 parse_ctx->packet->buffer,
434                                 parse_ctx->normal);
435       if (ret < 0) {
436         SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s] [%s]",
437                           sock->hostname, sock->port,
438                           silc_get_packet_name(parse_ctx->packet->type),
439                           (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
440                            sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
441                            sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
442                            "Router")));
443         memset(tmp, 0, sizeof(tmp));
444         silc_packet_context_free(parse_ctx->packet);
445         silc_free(parse_ctx);
446         silc_socket_free(sock);
447         return FALSE;
448       }
449     }
450     silc_buffer_push(parse_ctx->packet->buffer, block_len);
451
452     SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d",
453                       parse_ctx->packet->buffer->len),
454                      parse_ctx->packet->buffer->data,
455                      parse_ctx->packet->buffer->len);
456
457     /* Pull the packet from inbuf thus we'll get the next one
458        in the inbuf. */
459     silc_buffer_pull(sock->inbuf, paddedlen + mac_len);
460
461     /* Call the parser */
462     cont = (*parser)(parse_ctx, parser_context);
463
464     /* See if socket disconnected while parsing the packet */
465     if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
466       SILC_LOG_DEBUG(("Abandoning packet processing, socket disconnected"));
467       cont = FALSE;
468     }
469
470     memset(tmp, 0, sizeof(tmp));
471   }
472
473   /* Don't clear buffer if pending data is in the buffer */
474   if (cont == FALSE && sock->inbuf->len > 0) {
475     silc_socket_free(sock);
476     return TRUE;
477   }
478
479   /* Don't clear buffer if QoS data exists in the buffer */
480   if (sock->qos && sock->qos->data_len > 0) {
481     silc_socket_free(sock);
482     return TRUE;
483   }
484
485   SILC_LOG_DEBUG(("Clearing inbound buffer"));
486   silc_buffer_clear(sock->inbuf);
487   silc_socket_free(sock);
488   return TRUE;
489 }
490
491 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
492
493 static bool silc_packet_check_mac(SilcHmac hmac,
494                                   const unsigned char *data,
495                                   SilcUInt32 data_len,
496                                   const unsigned char *packet_mac,
497                                   SilcUInt32 sequence)
498 {
499   /* Check MAC */
500   if (hmac) {
501     unsigned char mac[32], psn[4];
502     SilcUInt32 mac_len;
503
504     SILC_LOG_DEBUG(("Verifying MAC"));
505
506     /* Compute HMAC of packet */
507     silc_hmac_init(hmac);
508     SILC_PUT32_MSB(sequence, psn);
509     silc_hmac_update(hmac, psn, 4);
510     silc_hmac_update(hmac, data, data_len);
511     silc_hmac_final(hmac, mac, &mac_len);
512
513     /* Compare the MAC's */
514     if (memcmp(packet_mac, mac, mac_len)) {
515       SILC_LOG_ERROR(("MAC failed"));
516       return FALSE;
517     }
518
519     SILC_LOG_DEBUG(("MAC is Ok"));
520   }
521
522   return TRUE;
523 }
524
525 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
526    Return 0 when packet is normal and 1 when it it special, -1 on error. */
527
528 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
529                                SilcUInt32 sequence, SilcBuffer buffer,
530                                bool normal)
531 {
532   /* If the packet type is not any special type lets decrypt rest
533      of the packet here. */
534   if (normal == TRUE) {
535     if (cipher) {
536       /* Decrypt rest of the packet */
537       SILC_LOG_DEBUG(("Decrypting the packet"));
538       if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
539                                buffer->len, NULL)) {
540         SILC_LOG_ERROR(("silc_cipher_decrypt failed"));
541         return -1;
542       }
543     }
544     return 0;
545
546   } else {
547     /* Decrypt rest of the header plus padding */
548     if (cipher) {
549       SilcUInt16 len;
550       SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
551
552       SILC_LOG_DEBUG(("Decrypting the header"));
553
554       /* padding length + src id len + dst id len + header length - 16
555          bytes already decrypted, gives the rest of the encrypted packet */
556       silc_buffer_push(buffer, block_len);
557       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
558               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
559              block_len);
560       silc_buffer_pull(buffer, block_len);
561
562       if (len > buffer->len) {
563         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
564                         "packet dropped"));
565         return -1;
566       }
567       if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
568                                len, NULL)) {
569         SILC_LOG_ERROR(("silc_cipher_decrypt failed"));
570         return -1;
571       }
572     }
573
574     return 1;
575   }
576 }
577
578 /* Parses the packet. This is called when a whole packet is ready to be
579    parsed. The buffer sent must be already decrypted before calling this
580    function. The len argument must be the true length of the packet. This
581    function returns the type of the packet. The data section of the
582    buffer is parsed, not head or tail sections. */
583
584 SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
585 {
586   SilcBuffer buffer = ctx->buffer;
587   SilcUInt8 tmp;
588   int len, ret;
589   SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
590
591   SILC_LOG_DEBUG(("Parsing incoming packet"));
592
593   /* Check the length of the buffer */
594   if (buffer->len < SILC_PACKET_MIN_LEN) {
595     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
596     return SILC_PACKET_NONE;
597   }
598
599   /* Parse the buffer. This parses the SILC header of the packet. */
600   len = silc_buffer_unformat(buffer,
601                              SILC_STR_UI_SHORT(&ctx->truelen),
602                              SILC_STR_UI_CHAR(&ctx->flags),
603                              SILC_STR_UI_CHAR(&ctx->type),
604                              SILC_STR_UI_CHAR(&padlen),
605                              SILC_STR_UI_CHAR(&tmp),
606                              SILC_STR_UI_CHAR(&src_id_len),
607                              SILC_STR_UI_CHAR(&dst_id_len),
608                              SILC_STR_UI_CHAR(&src_id_type),
609                              SILC_STR_END);
610   if (len == -1 || tmp != 0)
611     return SILC_PACKET_NONE;
612
613   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
614       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
615     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
616                     src_id_len, dst_id_len));
617     return SILC_PACKET_NONE;
618   }
619
620   silc_buffer_pull(buffer, len);
621   ret = silc_buffer_unformat(buffer,
622                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
623                                                         src_id_len),
624                              SILC_STR_UI_CHAR(&dst_id_type),
625                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
626                                                         dst_id_len),
627                              SILC_STR_UI_XNSTRING(NULL, padlen),
628                              SILC_STR_END);
629   if (ret == -1)
630     return SILC_PACKET_NONE;
631
632   if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
633     SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
634                    src_id_type, dst_id_type));
635     return SILC_PACKET_NONE;
636   }
637
638   ctx->src_id_len = src_id_len;
639   ctx->dst_id_len = dst_id_len;
640   ctx->src_id_type = src_id_type;
641   ctx->dst_id_type = dst_id_type;
642   ctx->padlen = padlen;
643
644   silc_buffer_push(buffer, len);
645
646   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
647                    ctx->buffer->data, ctx->buffer->len);
648
649   /* Pull SILC header and padding from packet */
650   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
651                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
652
653   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
654
655   return ctx->type;
656 }
657
658 /* Perform special SILC Packet header parsing. This is required to some
659    packet types that have the data payload encrypted with different key
660    than the header area plus padding of the packet. Hence, this parses
661    the header in a way that it does not take the data area into account
662    and parses the header and padding area only. */
663
664 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
665                                          SilcCipher cipher)
666 {
667   SilcBuffer buffer = ctx->buffer;
668   SilcUInt8 tmp;
669   int len, ret;
670   SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
671
672   SILC_LOG_DEBUG(("Parsing incoming packet"));
673
674   /* Check the length of the buffer */
675   if (buffer->len < SILC_PACKET_MIN_LEN) {
676     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
677     return SILC_PACKET_NONE;
678   }
679
680   /* Parse the buffer. This parses the SILC header of the packet. */
681   len = silc_buffer_unformat(buffer,
682                              SILC_STR_UI_SHORT(&ctx->truelen),
683                              SILC_STR_UI_CHAR(&ctx->flags),
684                              SILC_STR_UI_CHAR(&ctx->type),
685                              SILC_STR_UI_CHAR(&padlen),
686                              SILC_STR_UI_CHAR(&tmp),
687                              SILC_STR_UI_CHAR(&src_id_len),
688                              SILC_STR_UI_CHAR(&dst_id_len),
689                              SILC_STR_UI_CHAR(&src_id_type),
690                              SILC_STR_END);
691   if (len == -1 || tmp != 0) {
692     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
693     return SILC_PACKET_NONE;
694   }
695
696   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
697       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
698     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
699                     src_id_len, dst_id_len));
700     return SILC_PACKET_NONE;
701   }
702
703   silc_buffer_pull(buffer, len);
704   ret = silc_buffer_unformat(buffer,
705                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
706                                                         src_id_len),
707                              SILC_STR_UI_CHAR(&dst_id_type),
708                              SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
709                                                         dst_id_len),
710                              SILC_STR_UI_XNSTRING(NULL, padlen),
711                              SILC_STR_END);
712   if (ret == -1) {
713     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
714     return SILC_PACKET_NONE;
715   }
716
717   if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
718     SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
719                    src_id_type, dst_id_type));
720     return SILC_PACKET_NONE;
721   }
722
723   ctx->src_id_len = src_id_len;
724   ctx->dst_id_len = dst_id_len;
725   ctx->src_id_type = src_id_type;
726   ctx->dst_id_type = dst_id_type;
727   ctx->padlen = padlen;
728
729   silc_buffer_push(buffer, len);
730
731   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
732                    ctx->buffer->data, ctx->buffer->len);
733
734   /* Pull SILC header and padding from packet */
735   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
736                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
737
738   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
739
740   return ctx->type;
741 }
742
743 /* Allocate packet context */
744
745 SilcPacketContext *silc_packet_context_alloc(void)
746 {
747   SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
748   if (!ctx)
749     return NULL;
750   ctx->users++;
751   return ctx;
752 }
753
754 /* Increse the reference count of the packet context. */
755
756 SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
757 {
758   ctx->users++;
759   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users - 1,
760                   ctx->users));
761   return ctx;
762 }
763
764 /* Decrese the reference count of the packet context and free it only if
765    it is zero. */
766
767 void silc_packet_context_free(SilcPacketContext *ctx)
768 {
769   ctx->users--;
770   SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users + 1,
771                   ctx->users));
772   if (ctx->users < 1)
773     {
774       if (ctx->buffer)
775         silc_buffer_free(ctx->buffer);
776       if (ctx->src_id)
777         silc_free(ctx->src_id);
778       if (ctx->dst_id)
779         silc_free(ctx->dst_id);
780       silc_free(ctx);
781     }
782 }