Moved all the generic packet sending, enryption, reception,
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * Created: Fri Jul 25 18:52:14 1997
22  */
23 /*
24  * $Id$
25  * $Log$
26  * Revision 1.3  2000/07/14 06:10:15  priikone
27  *      Moved all the generic packet sending, enryption, reception,
28  *      decryption and processing function from client and server to
29  *      here as they were duplicated code in the applications. Now they
30  *      are generic code over generic API. Some functions were rewritter;
31  *      packet reception and HMAC computation and checking is now more
32  *      optimized.
33  *
34  * Revision 1.2  2000/07/05 06:06:35  priikone
35  *      Global cosmetic change.
36  *
37  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
38  *      Imported from internal CVS/Added Log headers.
39  *
40  *
41  */
42
43 #include "silcincludes.h"
44
45 /******************************************************************************
46
47                           Packet Sending Routines
48
49 ******************************************************************************/
50
51 /* Writes data from encrypted buffer to the socket connection. If the
52    data cannot be written at once, it will be written later with a timeout. 
53    The data is written from the data section of the buffer, not from head
54    or tail section. This automatically pulls the data section towards end
55    after writing the data. */
56
57 int silc_packet_write(int sock, SilcBuffer src)
58 {
59   int ret = 0;
60
61   SILC_LOG_DEBUG(("Writing data to socket %d", sock));
62
63   if (src->len > 0) {
64     ret = write(sock, src->data, src->len);
65     if (ret < 0) {
66       if (errno == EAGAIN) {
67         SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
68         return -2;
69       }
70       SILC_LOG_ERROR(("Cannot write to socket: %s", strerror(errno)));
71       return -1;
72     }
73
74     silc_buffer_pull(src, ret);
75   }
76
77   SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
78
79   return ret;
80 }
81
82 /* Actually sends the packet. This flushes the connections outgoing data
83    buffer. If data is sent directly to the network this returns the bytes
84    written, if error occured this returns -1 and if the data could not
85    be written directly to the network at this time this returns -2, in
86    which case the data should be queued by the caller and sent at some
87    later time. If `force_send' is TRUE this attempts to write the data
88    directly to the network, if FALSE, this returns -2. */
89
90 int silc_packet_send(SilcSocketConnection sock, int force_send)
91 {
92   /* Send now if forced to do so */
93   if (force_send == TRUE) {
94     int ret;
95
96     SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
97
98     /* Write to network */
99     ret = silc_packet_write(sock->sock, sock->outbuf);
100
101     if (ret == -1)
102       SILC_LOG_ERROR(("Error sending packet, dropped"));
103     if (ret != -2)
104       return ret;
105
106     SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
107   }  
108
109   SILC_LOG_DEBUG(("Packet in queue"));
110
111   return -2;
112 }
113
114 /* Encrypts a packet. This also creates HMAC of the packet before 
115    encryption and adds the HMAC at the end of the buffer. This assumes
116    that there is enough free space at the end of the buffer to add the
117    computed HMAC. This is the normal way of encrypting packets, if some
118    other process of HMAC computing and encryption is needed this function
119    cannot be used. */
120
121 void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, 
122                          SilcBuffer buffer, unsigned int len)
123 {
124   unsigned char mac[32];
125
126   if (cipher) {
127     SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)", 
128                     cipher->cipher->name, len, len - 2));
129   }
130
131   /* Compute HMAC. This assumes that HMAC is created from the entire
132      data area thus this uses the length found in buffer, not the length
133      sent as argument. */
134   if (hmac) {
135     silc_hmac_make(hmac, buffer->data, buffer->len, mac);
136     silc_buffer_put_tail(buffer, mac, hmac->hash->hash->hash_len);
137     memset(mac, 0, sizeof(mac));
138   }
139
140   /* Encrypt the data area of the packet. 2 bytes of the packet
141      are not encrypted. */
142   if (cipher)
143     cipher->cipher->encrypt(cipher->context, buffer->data + 2, 
144                             buffer->data + 2, len - 2, cipher->iv);
145
146   /* Pull the HMAC into the visible data area in the buffer */
147   if (hmac)
148     silc_buffer_pull_tail(buffer, hmac->hash->hash->hash_len);
149 }
150
151 /* Assembles a new packet to be ready for send out. The buffer sent as
152    argument must include the data to be sent and it must not be encrypted. 
153    The packet also must have enough free space so that the SILC header
154    and padding maybe added to the packet. The packet is encrypted after 
155    this function has returned.
156
157    The buffer sent as argument should be something like following:
158
159    --------------------------------------------
160    | head             | data           | tail |
161    --------------------------------------------
162    ^                  ^
163    58 bytes           x bytes
164
165    So that the SILC header and 1 - 16 bytes of padding can fit to
166    the buffer. After assembly the buffer might look like this:
167
168    --------------------------------------------
169    | data                              |      |
170    --------------------------------------------
171    ^                                   ^
172    Start of assembled packet
173
174    Packet construct is as follows (* = won't be encrypted):
175
176    x bytes       SILC Header
177       2 bytes     Payload length  (*)
178       1 byte      Flags
179       1 byte      Packet type
180       1 byte      Source ID Type
181       2 bytes     Source ID Length
182       x bytes     Source ID
183       1 byte      Destination ID Type
184       2 bytes     Destination ID Length
185       x bytes     Destination ID
186
187    1 - 16 bytes    Padding
188
189    x bytes        Data payload
190
191    All fields in the packet will be authenticated by MAC. The MAC is
192    not computed here, it must be computed differently before encrypting
193    the packet.
194
195 */
196
197 void silc_packet_assemble(SilcPacketContext *ctx)
198 {
199   unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
200   int i;
201
202   SILC_LOG_DEBUG(("Assembling outgoing packet"));
203   
204   /* Get the true length of the packet. This is saved as payload length
205      into the packet header. This does not include the length of the
206      padding. */
207   if (!ctx->truelen)
208     ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN + 
209       ctx->src_id_len + ctx->dst_id_len;
210
211   /* Calculate the length of the padding. The padding is calculated from
212      the data that will be encrypted. As protocol states 3 first bytes
213      of the packet are not encrypted they are not included in the
214      padding calculation. */
215   if (!ctx->padlen)
216     ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
217
218   /* Put the start of the data section to the right place. */
219   silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
220                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
221
222   /* Get random padding */
223 #if 1
224   for (i = 0; i < ctx->padlen; i++)
225     tmppad[i] = silc_rng_get_byte(ctx->rng);
226 #else
227   /* XXX: For testing - to be removed */
228   memset(tmppad, 65, sizeof(tmppad));
229 #endif
230
231   /* Create the packet. This creates the SILC header and adds padding,
232      rest of the buffer remains as it is. */
233   silc_buffer_format(ctx->buffer, 
234                      SILC_STR_UI_SHORT(ctx->truelen),
235                      SILC_STR_UI_CHAR(ctx->flags),
236                      SILC_STR_UI_CHAR(ctx->type),
237                      SILC_STR_UI_SHORT(ctx->src_id_len),
238                      SILC_STR_UI_SHORT(ctx->dst_id_len),
239                      SILC_STR_UI_CHAR(ctx->src_id_type),
240                      SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
241                      SILC_STR_UI_CHAR(ctx->dst_id_type),
242                      SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
243                      SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
244                      SILC_STR_END);
245
246   SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len), 
247                    ctx->buffer->data, ctx->buffer->len);
248
249   SILC_LOG_DEBUG(("Outgoing packet assembled"));
250 }
251
252 /* Prepare outgoing data buffer for packet sending. This moves the data
253    area so that new packet may be added into it. If needed this allocates
254    more space to the buffer. This handles directly the connection's
255    outgoing buffer in SilcSocketConnection object. */
256
257 void silc_packet_send_prepare(SilcSocketConnection sock,
258                               unsigned int header_len,
259                               unsigned int padlen,
260                               unsigned int data_len)
261 {
262   int totlen, oldlen;
263
264   totlen = header_len + padlen + data_len;
265
266   /* Prepare the outgoing buffer for packet sending. */
267   if (!sock->outbuf) {
268     /* Allocate new buffer. This is done only once per connection. */
269     SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
270     
271     sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
272     silc_buffer_pull_tail(sock->outbuf, totlen);
273     silc_buffer_pull(sock->outbuf, header_len + padlen);
274   } else {
275     if (SILC_IS_OUTBUF_PENDING(sock)) {
276       /* There is some pending data in the buffer. */
277
278       /* Allocate more space if needed */
279       if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
280         SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
281         sock->outbuf = silc_buffer_realloc(sock->outbuf, 
282                                            sock->outbuf->truelen + totlen);
283       }
284
285       oldlen = sock->outbuf->len;
286       silc_buffer_pull_tail(sock->outbuf, totlen);
287       silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
288     } else {
289       /* Buffer is free for use */
290       silc_buffer_clear(sock->outbuf);
291       silc_buffer_pull_tail(sock->outbuf, totlen);
292       silc_buffer_pull(sock->outbuf, header_len + padlen);
293     }
294   }
295 }
296
297 /******************************************************************************
298
299                          Packet Reception Routines
300
301 ******************************************************************************/
302
303 /* Reads data from the socket connection into the incoming data buffer.
304    However, this does not parse the packet, it only reads some amount from
305    the network. If there are more data available that can be read at a time
306    the rest of the data will be read later with a timeout and only after
307    that the packet is ready to be parsed. 
308
309    The destination buffer sent as argument must be initialized before 
310    calling this function, and, the data section and the start of the tail
311    section must be same. Ie. we add the read data to the tail section of
312    the buffer hence the data section is the start of the buffer.
313
314    This returns amount of bytes read or -1 on error or -2 on case where
315    all of the data could not be read at once. */
316
317 int silc_packet_read(int sock, SilcBuffer dest)
318 {
319   int len = 0;
320   unsigned char buf[SILC_PACKET_READ_SIZE];
321
322   SILC_LOG_DEBUG(("Reading data from socket %d", sock));
323
324   /* Read the data from the socket. */
325   len = read(sock, buf, sizeof(buf));
326   if (len < 0) {
327     if (errno == EAGAIN) {
328       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
329       return -2;
330     }
331     SILC_LOG_ERROR(("Cannot read from socket: %d", strerror(errno)));
332     return -1;
333   }
334
335   if (!len)
336     return 0;
337
338   /* Insert the data to the buffer. If the data doesn't fit to the 
339      buffer space is allocated for the buffer. */
340   /* XXX: This may actually be bad thing as if there is pending data in
341      the buffer they will be lost! */
342   if (dest) {
343
344     /* If the data doesn't fit we just have to allocate a whole new 
345        data area */
346     if (dest->truelen <= len) {
347
348       /* Free the old buffer */
349       memset(dest->head, 'F', dest->truelen);
350       silc_free(dest->head);
351
352       /* Allocate new data area */
353       len += SILC_PACKET_DEFAULT_SIZE;
354       dest->data = silc_calloc(len, sizeof(char));
355       dest->truelen = len;
356       dest->len = 0;
357       dest->head = dest->data;
358       dest->data = dest->data;
359       dest->tail = dest->data;
360       dest->end = dest->data + dest->truelen;
361       len -= SILC_PACKET_DEFAULT_SIZE;
362     }
363
364     silc_buffer_put_tail(dest, buf, len);
365     silc_buffer_pull_tail(dest, len);
366   }
367
368   SILC_LOG_DEBUG(("Read %d bytes", len));
369
370   return len;
371 }
372
373 /* Processes the received data. This checks the received data and 
374    calls parser callback that handles the actual packet decryption
375    and parsing. If more than one packet was received this calls the
376    parser multiple times. The parser callback will get context
377    SilcPacketParserContext that includes the packet and the `context'
378    sent to this function. Returns TRUE on success and FALSE on error. */
379
380 int silc_packet_receive_process(SilcSocketConnection sock, 
381                                 SilcCipher cipher, SilcHmac hmac,
382                                 SilcPacketParserCallback parser, 
383                                 void *context)
384 {
385   SilcPacketParserContext *parse_ctx;
386   int packetlen, paddedlen, mac_len = 0;
387
388   /* Check whether we received a whole packet. If reading went without
389      errors we either read a whole packet or the read packet is 
390      incorrect and will be dropped. */
391   SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
392   if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
393     SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
394     silc_buffer_clear(sock->inbuf);
395     return FALSE;
396   }
397
398   /* Parse the packets from the data */
399   if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
400     /* Received possibly many packets at once */
401
402     if (hmac)
403       mac_len = hmac->hash->hash->hash_len;
404
405     while(sock->inbuf->len > 0) {
406       SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
407
408       if (sock->inbuf->len < paddedlen) {
409         SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
410         return FALSE;
411       }
412
413       paddedlen += 2;
414       parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
415       parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
416       parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
417       parse_ctx->sock = sock;
418       parse_ctx->cipher = cipher;
419       parse_ctx->hmac = hmac;
420       parse_ctx->context = context;
421
422       silc_buffer_pull_tail(parse_ctx->packet->buffer, 
423                             SILC_BUFFER_END(parse_ctx->packet->buffer));
424       silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
425                       paddedlen + mac_len);
426
427       SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
428                         parse_ctx->packet->buffer->len),
429                        parse_ctx->packet->buffer->data, 
430                        parse_ctx->packet->buffer->len);
431
432       /* Call the parser */
433       if (parser)
434         (*parser)(parse_ctx);
435
436       /* Pull the packet from inbuf thus we'll get the next one
437          in the inbuf. */
438       silc_buffer_pull(sock->inbuf, paddedlen);
439       if (hmac)
440         silc_buffer_pull(sock->inbuf, mac_len);
441     }
442
443     /* All packets are processed, return successfully. */
444     silc_buffer_clear(sock->inbuf);
445     return TRUE;
446
447   } else {
448     /* Received one packet */
449     
450     SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
451                      sock->inbuf->data, sock->inbuf->len);
452
453     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
454     parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
455     parse_ctx->packet->buffer = silc_buffer_copy(sock->inbuf);
456     parse_ctx->sock = sock;
457     parse_ctx->cipher = cipher;
458     parse_ctx->hmac = hmac;
459     parse_ctx->context = context;
460     silc_buffer_clear(sock->inbuf);
461
462     /* Call the parser */
463     if (parser)
464       (*parser)(parse_ctx);
465
466     /* Return successfully */
467     return TRUE;
468   }
469 }
470
471 /* Receives packet from network and reads the data into connection's
472    incoming data buffer. If the data was read directly this returns the
473    read bytes, if error occured this returns -1, if the data could not
474    be read directly at this time this returns -2 in which case the data
475    should be read again at some later time, or If EOF occured this returns
476    0. */
477
478 int silc_packet_receive(SilcSocketConnection sock)
479 {
480   int ret;
481
482   /* Allocate the incoming data buffer if not done already. */
483   if (!sock->inbuf)
484     sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
485   
486   /* Read some data from connection */
487   ret = silc_packet_read(sock->sock, sock->inbuf);
488
489   /* Error */
490   if (ret == -1)
491     SILC_LOG_ERROR(("Error reading packet, dropped"));
492
493   return ret;
494 }
495
496 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
497    after packet has been totally decrypted and parsed. */
498
499 static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer)
500 {
501   /* Check MAC */
502   if (hmac) {
503     unsigned char mac[32];
504     
505     SILC_LOG_DEBUG(("Verifying MAC"));
506
507     /* Compute HMAC of packet */
508     memset(mac, 0, sizeof(mac));
509     silc_hmac_make(hmac, buffer->data, buffer->len, mac);
510
511     /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
512     if (memcmp(mac, buffer->tail, hmac->hash->hash->hash_len)) {
513       SILC_LOG_DEBUG(("MAC failed"));
514       return FALSE;
515     }
516     
517     SILC_LOG_DEBUG(("MAC is Ok"));
518     memset(mac, 0, sizeof(mac));
519   }
520   
521   return TRUE;
522 }
523
524 /* Decrypts rest of the packet (after decrypting just the SILC header).
525    After calling this function the packet is ready to be parsed by calling 
526    silc_packet_parse. If everything goes without errors this returns TRUE,
527    if packet is malformed this returns FALSE. */
528
529 static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
530                                     SilcBuffer buffer)
531 {
532   if (cipher) {
533
534     /* Pull MAC from packet before decryption */
535     if (hmac) {
536       if ((buffer->len - hmac->hash->hash->hash_len) > SILC_PACKET_MIN_LEN) {
537         silc_buffer_push_tail(buffer, hmac->hash->hash->hash_len);
538       } else {
539         SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
540         return FALSE;
541       }
542     }
543
544     SILC_LOG_DEBUG(("Decrypting rest of the packet"));
545
546     /* Decrypt rest of the packet */
547     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
548     cipher->cipher->decrypt(cipher->context, buffer->data + 2,
549                             buffer->data + 2, buffer->len - 2,
550                             cipher->iv);
551     silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
552
553     SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
554                      buffer->data, buffer->len);
555   }
556
557   return TRUE;
558 }
559
560 /* Decrypts rest of the SILC Packet header that has been decrypted partly
561    already. This decrypts the padding of the packet also. After calling 
562    this function the packet is ready to be parsed by calling function 
563    silc_packet_parse. This is used in special packet reception (protocol
564    defines the way of decrypting special packets). */
565
566 static int silc_packet_decrypt_rest_special(SilcCipher cipher,
567                                             SilcHmac hmac,
568                                             SilcBuffer buffer)
569 {
570   /* Decrypt rest of the header plus padding */
571   if (cipher) {
572     unsigned short truelen, len1, len2, padlen;
573
574     /* Pull MAC from packet before decryption */
575     if (hmac) {
576       if ((buffer->len - hmac->hash->hash->hash_len) > SILC_PACKET_MIN_LEN) {
577         silc_buffer_push_tail(buffer, hmac->hash->hash->hash_len);
578       } else {
579         SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
580         return FALSE;
581       }
582     }
583   
584     SILC_LOG_DEBUG(("Decrypting rest of the header"));
585
586     SILC_GET16_MSB(len1, &buffer->data[4]);
587     SILC_GET16_MSB(len2, &buffer->data[6]);
588
589     truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
590     padlen = SILC_PACKET_PADLEN(truelen);
591     len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
592
593     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
594     cipher->cipher->decrypt(cipher->context, buffer->data + 2,
595                             buffer->data + 2, len1 - 2,
596                             cipher->iv);
597     silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
598   }
599
600   return TRUE;
601 }
602
603 /* Decrypts a packet. This assumes that typical SILC packet is the
604    packet to be decrypted and thus checks for normal and special SILC
605    packets and can handle both of them. This also computes and checks
606    the HMAC of the packet. If any other special or customized decryption
607    processing is required this function cannot be used. This returns
608    -1 on error, 0 when packet is normal packet and 1 when the packet
609    is special and requires special processing. */
610
611 int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
612                         SilcBuffer buffer, SilcPacketContext *packet)
613 {
614 #if 0
615   SILC_LOG_DEBUG(("Decrypting packet, cipher %s, len %d (%d)", 
616                   cipher->cipher->name, len, len - 2));
617 #endif
618
619   /* Decrypt start of the packet header */
620   if (cipher)
621     cipher->cipher->decrypt(cipher->context, buffer->data + 2,
622                             buffer->data + 2, SILC_PACKET_MIN_HEADER_LEN - 2,
623                             cipher->iv);
624
625   /* If the packet type is not any special type lets decrypt rest
626      of the packet here. */
627   if ((buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
628       !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) ||
629       buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE) {
630
631     /* Normal packet, decrypt rest of the packet */
632     if (!silc_packet_decrypt_rest(cipher, hmac, buffer))
633       return -1;
634
635     /* Check MAC */
636     if (!silc_packet_check_mac(hmac, buffer))
637       return FALSE;
638
639     return 0;
640   } else {
641     /* Packet requires special handling, decrypt rest of the header.
642        This only decrypts. */
643     silc_packet_decrypt_rest_special(cipher, hmac, buffer);
644
645     /* Check MAC */
646     if (!silc_packet_check_mac(hmac, buffer))
647       return FALSE;
648
649     return 1;
650   }
651 }
652
653 /* Parses the packet. This is called when a whole packet is ready to be
654    parsed. The buffer sent must be already decrypted before calling this 
655    function. The len argument must be the true length of the packet. This 
656    function returns the type of the packet. The data section of the 
657    buffer is parsed, not head or tail sections. */
658
659 SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
660 {
661   SilcBuffer buffer = ctx->buffer;
662   int len;
663
664   SILC_LOG_DEBUG(("Parsing incoming packet"));
665
666   /* Check the length of the buffer */
667   if (buffer->len < SILC_PACKET_MIN_LEN) {
668     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
669     return SILC_PACKET_NONE;
670   }
671
672   /* Parse the buffer. This parses the SILC header of the packet. */
673   len = silc_buffer_unformat(buffer, 
674                              SILC_STR_UI_SHORT(&ctx->truelen),
675                              SILC_STR_UI_CHAR(&ctx->flags),
676                              SILC_STR_UI_CHAR(&ctx->type),
677                              SILC_STR_UI_SHORT(&ctx->src_id_len),
678                              SILC_STR_UI_SHORT(&ctx->dst_id_len),
679                              SILC_STR_UI_CHAR(&ctx->src_id_type),
680                              SILC_STR_END);
681
682   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
683       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
684     SILC_LOG_ERROR(("Bad ID lengths in packet"));
685     return SILC_PACKET_NONE;
686   }
687
688   /* Calculate length of padding in packet */
689   ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
690
691   silc_buffer_pull(buffer, len);
692   silc_buffer_unformat(buffer, 
693                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
694                                                   ctx->src_id_len),
695                        SILC_STR_UI_CHAR(&ctx->dst_id_type),
696                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
697                                                   ctx->dst_id_len),
698                        SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
699                        SILC_STR_END);
700   silc_buffer_push(buffer, len);
701
702   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
703                    ctx->buffer->data, ctx->buffer->len);
704
705   /* Pull SILC header and padding from packet */
706   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
707                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
708
709   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
710
711   return ctx->type;
712 }
713
714 /* Perform special SILC Packet header parsing. This is required to some
715    packet types that have the data payload encrypted with different key
716    than the header area plus padding of the packet. Hence, this parses
717    the header in a way that it does not take the data area into account
718    and parses the header and padding area only. */
719
720 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
721 {
722   SilcBuffer buffer = ctx->buffer;
723   int len, tmplen;
724
725   SILC_LOG_DEBUG(("Parsing incoming packet"));
726
727   /* Check the length of the buffer */
728   if (buffer->len < SILC_PACKET_MIN_LEN) {
729     SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
730     return SILC_PACKET_NONE;
731   }
732
733   /* Parse the buffer. This parses the SILC header of the packet. */
734   len = silc_buffer_unformat(buffer, 
735                              SILC_STR_UI_SHORT(&ctx->truelen),
736                              SILC_STR_UI_CHAR(&ctx->flags),
737                              SILC_STR_UI_CHAR(&ctx->type),
738                              SILC_STR_UI_SHORT(&ctx->src_id_len),
739                              SILC_STR_UI_SHORT(&ctx->dst_id_len),
740                              SILC_STR_UI_CHAR(&ctx->src_id_type),
741                              SILC_STR_END);
742
743   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
744       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
745     SILC_LOG_ERROR(("Bad ID lengths in packet"));
746     return SILC_PACKET_NONE;
747   }
748
749   /* Calculate length of padding in packet. As this is special packet
750      the data area is not used in the padding calculation as it won't
751      be decrypted by the caller. */
752   tmplen = SILC_PACKET_HEADER_LEN + ctx->src_id_len + ctx->dst_id_len;
753   ctx->padlen = SILC_PACKET_PADLEN(tmplen);
754
755   silc_buffer_pull(buffer, len);
756   silc_buffer_unformat(buffer, 
757                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
758                                                   ctx->src_id_len),
759                        SILC_STR_UI_CHAR(&ctx->dst_id_type),
760                        SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
761                                                   ctx->dst_id_len),
762                        SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
763                        SILC_STR_END);
764   silc_buffer_push(buffer, len);
765
766   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
767                    ctx->buffer->data, ctx->buffer->len);
768
769   /* Pull SILC header and padding from packet */
770   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
771                    ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
772
773   SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
774
775   return ctx->type;
776 }