New silcconfig library and server parser. Merged silc-newconfig-final.patch.
[silc.git] / apps / silcd / packet_send.c
index 6764fb8c23beb88e96b666a8a132b6189e9cc18b..d2d21517068d73afe44e4b0cf78d543a2fad3669 100644 (file)
@@ -2,7 +2,7 @@
 
   packet_send.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
   Copyright (C) 1997 - 2001 Pekka Riikonen
 
 
 int silc_server_packet_send_real(SilcServer server,
                                 SilcSocketConnection sock,
-                                int force_send)
+                                bool force_send)
 {
   int ret;
 
+  /* If disconnecting, ignore the data */
+  if (SILC_IS_DISCONNECTING(sock))
+    return -1;
+
   /* If rekey protocol is active we must assure that all packets are
      sent through packet queue. */
   if (SILC_SERVER_IS_REKEY(sock))
     force_send = FALSE;
 
+  /* If outbound data is already pending do not force send */
+  if (SILC_IS_OUTBUF_PENDING(sock))
+    force_send = FALSE;
+
   /* Send the packet */
   ret = silc_packet_send(sock, force_send);
   if (ret != -2)
@@ -49,7 +57,7 @@ int silc_server_packet_send_real(SilcServer server,
      This call sets the connection both for input and output (the input
      is set always and this call keeps the input setting, actually). 
      Actual data sending is performed by silc_server_packet_process. */
-  SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+  SILC_SET_CONNECTION_FOR_OUTPUT(server->schedule, sock->sock);
 
   /* Mark to socket that data is pending in outgoing buffer. This flag
      is needed if new data is added to the buffer before the earlier
@@ -71,24 +79,37 @@ void silc_server_packet_send(SilcServer server,
                             SilcPacketFlags flags,
                             unsigned char *data, 
                             uint32 data_len,
-                            int force_send)
+                            bool force_send)
 {
   void *dst_id = NULL;
   SilcIdType dst_id_type = SILC_ID_NONE;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
 
   if (!sock)
     return;
 
+  /* If disconnecting, ignore the data */
+  if (SILC_IS_DISCONNECTING(sock))
+    return;
+
+  /* If entry is disabled do not sent anything. */
+  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+    return;
+
   /* Get data used in the packet sending, keys and stuff */
   switch(sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
-    dst_id = ((SilcClientEntry)sock->user_data)->id;
-    dst_id_type = SILC_ID_CLIENT;
+    if (sock->user_data) {
+      dst_id = ((SilcClientEntry)sock->user_data)->id;
+      dst_id_type = SILC_ID_CLIENT;
+    }
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
-    dst_id = ((SilcServerEntry)sock->user_data)->id;
-    dst_id_type = SILC_ID_SERVER;
+    if (sock->user_data) {
+      dst_id = ((SilcServerEntry)sock->user_data)->id;
+      dst_id_type = SILC_ID_SERVER;
+    }
     break;
   default:
     break;
@@ -113,37 +134,51 @@ void silc_server_packet_send_dest(SilcServer server,
                                  SilcIdType dst_id_type,
                                  unsigned char *data, 
                                  uint32 data_len,
-                                 int force_send)
+                                 bool force_send)
 {
   SilcPacketContext packetdata;
-  SilcIDListData idata;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  uint32 sequence = 0;
   unsigned char *dst_id_data = NULL;
   uint32 dst_id_len = 0;
+  int block_len = 0;
 
-  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+  /* If disconnecting, ignore the data */
+  if (SILC_IS_DISCONNECTING(sock))
+    return;
 
-  /* Get data used in the packet sending, keys and stuff */
-  idata = (SilcIDListData)sock->user_data;
+  /* If entry is disabled do not sent anything. */
+  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+    return;
+
+  SILC_LOG_DEBUG(("Sending packet, type %d", type));
 
   if (dst_id) {
     dst_id_data = silc_id_id2str(dst_id, dst_id_type);
-    dst_id_len = silc_id_get_len(dst_id_type);
+    dst_id_len = silc_id_get_len(dst_id, dst_id_type);
+  }
+
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
+    sequence = idata->psn_send++;
+    block_len = silc_cipher_get_block_len(cipher);
   }
 
   /* Set the packet context pointers */
   packetdata.type = type;
   packetdata.flags = flags;
   packetdata.src_id = silc_id_id2str(server->id, server->id_type);
-  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_len = silc_id_get_len(server->id, server->id_type);
   packetdata.src_id_type = server->id_type;
   packetdata.dst_id = dst_id_data;
   packetdata.dst_id_len = dst_id_len;
   packetdata.dst_id_type = dst_id_type;
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -162,17 +197,13 @@ void silc_server_packet_send_dest(SilcServer server,
     silc_buffer_put(sock->outbuf, data, data_len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
-  }
+  silc_packet_assemble(&packetdata, cipher);
 
   /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+  silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
 
-  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
@@ -202,16 +233,18 @@ void silc_server_packet_send_srcdest(SilcServer server,
                                     SilcIdType dst_id_type,
                                     unsigned char *data, 
                                     uint32 data_len,
-                                    int force_send)
+                                    bool force_send)
 {
   SilcPacketContext packetdata;
   SilcIDListData idata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
+  uint32 sequence = 0;
   unsigned char *dst_id_data = NULL;
   uint32 dst_id_len = 0;
   unsigned char *src_id_data = NULL;
   uint32 src_id_len = 0;
+  int block_len = 0;
 
   SILC_LOG_DEBUG(("Sending packet, type %d", type));
 
@@ -220,12 +253,19 @@ void silc_server_packet_send_srcdest(SilcServer server,
 
   if (dst_id) {
     dst_id_data = silc_id_id2str(dst_id, dst_id_type);
-    dst_id_len = silc_id_get_len(dst_id_type);
+    dst_id_len = silc_id_get_len(dst_id, dst_id_type);
   }
 
   if (src_id) {
     src_id_data = silc_id_id2str(src_id, src_id_type);
-    src_id_len = silc_id_get_len(src_id_type);
+    src_id_len = silc_id_get_len(src_id, src_id_type);
+  }
+
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
+    sequence = idata->psn_send++;
+    block_len = silc_cipher_get_block_len(cipher);
   }
 
   /* Set the packet context pointers */
@@ -239,7 +279,7 @@ void silc_server_packet_send_srcdest(SilcServer server,
   packetdata.dst_id_type = dst_id_type;
   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
 
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
@@ -258,17 +298,13 @@ void silc_server_packet_send_srcdest(SilcServer server,
     silc_buffer_put(sock->outbuf, data, data_len);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
-  }
+  silc_packet_assemble(&packetdata, cipher);
 
   /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+  silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
 
-  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
@@ -298,16 +334,17 @@ void silc_server_packet_broadcast(SilcServer server,
   /* If the packet is originated from our primary route we are
      not allowed to send the packet. */
   id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
-  if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
+  if (id && !SILC_ID_SERVER_COMPARE(id, server->router->id)) {
     idata = (SilcIDListData)sock->user_data;
 
     silc_buffer_push(buffer, buffer->data - buffer->head);
     silc_packet_send_prepare(sock, 0, 0, buffer->len); 
     silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
                        sock->outbuf, sock->outbuf->len);
 
-    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
+    SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1,
+                     sock->outbuf->len),
                     sock->outbuf->data, sock->outbuf->len);
 
     /* Now actually send the packet */
@@ -338,16 +375,89 @@ void silc_server_packet_route(SilcServer server,
   silc_buffer_push(buffer, buffer->data - buffer->head);
   silc_packet_send_prepare(sock, 0, 0, buffer->len); 
   silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-  silc_packet_encrypt(idata->send_key, idata->hmac_send, 
+  silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
                      sock->outbuf, sock->outbuf->len);
 
-  SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
   silc_server_packet_send_real(server, sock, TRUE);
 }
 
+/* This routine can be used to send a packet to table of clients provided
+   in `clients'. If `route' is FALSE the packet is routed only to local
+   clients (for server locally connected, and for router local cell). */
+
+void silc_server_packet_send_clients(SilcServer server,
+                                    SilcClientEntry *clients,
+                                    uint32 clients_count,
+                                    SilcPacketType type, 
+                                    SilcPacketFlags flags,
+                                    bool route,
+                                    unsigned char *data, 
+                                    uint32 data_len,
+                                    bool force_send)
+{
+  SilcSocketConnection sock = NULL;
+  SilcClientEntry client = NULL;
+  SilcServerEntry *routed = NULL;
+  uint32 routed_count = 0;
+  bool gone = FALSE;
+  int i, k;
+
+  SILC_LOG_DEBUG(("Sending packet to list of clients"));
+
+  /* Send to all clients in table */
+  for (i = 0; i < clients_count; i++) {
+    client = clients[i];
+
+    /* If client has router set it is not locally connected client and
+       we will route the message to the router set in the client. Though,
+       send locally connected server in all cases. */
+    if (server->server_type == SILC_ROUTER && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       continue;
+
+      /* Route only once to router */
+      sock = (SilcSocketConnection)client->router->connection;
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
+         continue;
+       gone = TRUE;
+      }
+
+      /* Send the packet */
+      silc_server_packet_send_dest(server, sock, type, flags,
+                                  client->router->id, SILC_ID_SERVER,
+                                  data, data_len, force_send);
+
+      /* Mark this route routed already */
+      routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+      routed[routed_count++] = client->router;
+      continue;
+    }
+
+    if (client->router)
+      continue;
+
+    /* Send to locally connected client */
+    sock = (SilcSocketConnection)client->connection;
+    silc_server_packet_send_dest(server, sock, type, flags,
+                                client->id, SILC_ID_CLIENT,
+                                data, data_len, force_send);
+  }
+
+  silc_free(routed);
+}
+
 /* Internal routine to actually create the channel packet and send it
    to network. This is common function in channel message sending. If
    `channel_message' is TRUE this encrypts the message as it is strictly
@@ -359,14 +469,28 @@ silc_server_packet_send_to_channel_real(SilcServer server,
                                        SilcPacketContext *packet,
                                        SilcCipher cipher,
                                        SilcHmac hmac,
+                                       uint32 sequence,
                                        unsigned char *data,
                                        uint32 data_len,
-                                       int channel_message,
-                                       int force_send)
+                                       bool channel_message,
+                                       bool force_send)
 {
+  int block_len;
+
+  if (!sock)
+    return;
+
   packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packet->src_id_len + packet->dst_id_len;
 
+  block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
+  if (channel_message)
+    packet->padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                        packet->src_id_len +
+                                        packet->dst_id_len), block_len);
+  else
+    packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len);
+
   /* Prepare outgoing data buffer for packet sending */
   silc_packet_send_prepare(sock, 
                           SILC_PACKET_HEADER_LEN +
@@ -378,17 +502,20 @@ silc_server_packet_send_to_channel_real(SilcServer server,
   packet->buffer = sock->outbuf;
 
   /* Put the data to buffer, assemble and encrypt the packet. The packet
-     is encrypted with normal session key shared with the client. */
+     is encrypted with normal session key shared with the client, unless
+     the `channel_message' is TRUE. */
   silc_buffer_put(sock->outbuf, data, data_len);
-  silc_packet_assemble(packet);
+  silc_packet_assemble(packet, cipher);
   if (channel_message)
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                       packet->src_id_len + packet->dst_id_len +
-                       packet->padlen);
+    silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, 
+                       SILC_PACKET_HEADER_LEN + packet->src_id_len + 
+                       packet->dst_id_len + packet->padlen);
   else
-    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+    silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, 
+                       sock->outbuf->len);
     
-  SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+  SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence, 
+                   sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
 
   /* Now actually send the packet */
@@ -402,28 +529,31 @@ silc_server_packet_send_to_channel_real(SilcServer server,
    If `route' is FALSE then the packet is sent only locally and will not
    be routed anywhere (for router locally means cell wide). If `sender'
    is provided then the packet is not sent to that connection since it
-   originally came from it. */
+   originally came from it. If `send_to_clients' is FALSE then the
+   packet is not sent clients, only servers. */
 
 void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
                                        SilcPacketType type,
-                                       unsigned char route,
+                                       bool route,
                                        unsigned char *data,
                                        uint32 data_len,
-                                       int force_send)
+                                       bool force_send)
 {
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl;
+  SilcHashTableList htl;
   SilcIDListData idata;
   uint32 routed_count = 0;
+  bool gone = FALSE;
+  int k;
 
   /* This doesn't send channel message packets */
-  if (type == SILC_PACKET_CHANNEL_MESSAGE)
-    return;
+  assert(type != SILC_PACKET_CHANNEL_MESSAGE);
   
   SILC_LOG_DEBUG(("Sending packet to channel"));
 
@@ -431,18 +561,15 @@ void silc_server_packet_send_to_channel(SilcServer server,
   packetdata.flags = 0;
   packetdata.type = type;
   packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
-  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
   packetdata.src_id_type = SILC_ID_SERVER;
   packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
-  if (route && server->server_type == SILC_SERVER && !server->standalone &&
+  if (route && server->server_type != SILC_ROUTER && !server->standalone &&
       channel->global_users) {
     SilcServerEntry router;
 
@@ -452,27 +579,32 @@ void silc_server_packet_send_to_channel(SilcServer server,
     idata = (SilcIDListData)router;
     
     if (sock != sender) {
-      SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+      SILC_LOG_DEBUG(("Sending packet to router for routing"));
       
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++,
                                              data, data_len, FALSE, 
                                              force_send);
     }
   }
 
+  routed = silc_calloc(silc_hash_table_count(channel->user_list), 
+                      sizeof(*routed));
+
   /* Send the message to clients on the channel's client list. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+  silc_hash_table_list(channel->user_list, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     client = chl->client;
+    if (!client)
+      continue;
 
     /* If client has router set it is not locally connected client and
        we will route the message to the router set in the client. Though,
        send locally connected server in all cases. */
-    if (server->server_type == SILC_ROUTER && client && client->router && 
+    if (server->server_type == SILC_ROUTER && client->router && 
        ((!route && client->router->router == server->id_entry) || route)) {
-      int k;
 
       /* Check if we have sent the packet to this route already */
       for (k = 0; k < routed_count; k++)
@@ -488,47 +620,49 @@ void silc_server_packet_send_to_channel(SilcServer server,
       if (sender && sock == sender)
        continue;
 
+      /* Route only once to router */
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
+         continue;
+       gone = TRUE;
+      }
+
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++,
                                              data, data_len, FALSE, 
                                              force_send);
 
-      /* We want to make sure that the packet is routed to same router
-        only once. Mark this route as sent route. */
-      k = routed_count;
-      routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
-      routed[k] = client->router;
-      routed_count++;
-
+      /* Mark this route routed already */
+      routed[routed_count++] = client->router;
       continue;
     }
 
-    if (client && client->router)
+    if (client->router)
       continue;
 
     /* Send to locally connected client */
-    if (client) {
-
-      /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)client->connection;
-      idata = (SilcIDListData)client;
 
-      if (sender && sock == sender)
-       continue;
+    /* Get data used in packet header encryption, keys and stuff. */
+    sock = (SilcSocketConnection)client->connection;
+    idata = (SilcIDListData)client;
+    
+    if (sender && sock == sender)
+      continue;
 
-      /* Send the packet */
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, 
-                                             idata->hmac_send, 
-                                             data, data_len, FALSE
-                                             force_send);
-    }
+    /* Send the packet */
+    silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                           idata->send_key, 
+                                           idata->hmac_send, 
+                                           idata->psn_send++
+                                           data, data_len, FALSE, 
+                                           force_send);
   }
 
-  if (routed_count)
-    silc_free(routed);
+  silc_hash_table_list_reset(&htl);
+  silc_free(routed);
   silc_free(packetdata.src_id);
   silc_free(packetdata.dst_id);
 }
@@ -537,7 +671,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
    then we'll need to encrypt it with the channel key. This is called
    from the silc_server_packet_relay_to_channel. */
 
-static void
+static bool
 silc_server_packet_relay_to_channel_encrypt(SilcServer server,
                                            SilcSocketConnection sock,
                                            SilcChannelEntry channel,
@@ -555,7 +689,7 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
       channel->channel_key) {
     SilcBuffer chp;
     uint32 iv_len, i;
-    uint16 data_len, flags;
+    uint16 dlen, flags;
 
     iv_len = silc_cipher_get_block_len(channel->channel_key);
     if (channel->iv[0] == '\0')
@@ -566,15 +700,22 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
     
     /* Encode new payload. This encrypts it also. */
     SILC_GET16_MSB(flags, data);
-    SILC_GET16_MSB(data_len, data + 2);
-    chp = silc_channel_message_payload_encode(flags, data_len, 
-                                             data + 4,
+    SILC_GET16_MSB(dlen, data + 2);
+
+    if (dlen > data_len) {
+      SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
+      return FALSE;
+    }
+
+    chp = silc_channel_message_payload_encode(flags, dlen, data + 4,
                                              iv_len, channel->iv,
                                              channel->channel_key,
                                              channel->hmac);
     memcpy(data, chp->data, chp->len);
     silc_buffer_free(chp);
   }
+
+  return TRUE;
 }
 
 /* This routine is explicitly used to relay messages to some channel.
@@ -594,7 +735,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                         void *sender_entry,
                                         unsigned char *data,
                                         uint32 data_len,
-                                        int force_send)
+                                        bool force_send)
 {
   bool found = FALSE;
   SilcSocketConnection sock = NULL;
@@ -604,37 +745,36 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   SilcChannelClientEntry chl;
   uint32 routed_count = 0;
   SilcIDListData idata;
+  SilcHashTableList htl;
+  bool gone = FALSE;
+  int k;
 
   SILC_LOG_DEBUG(("Relaying packet to channel"));
 
+  /* This encrypts the packet, if needed. It will be encrypted if
+     it came from the router thus it needs to be encrypted with the
+     channel key. If the channel key does not exist, then we know we
+     don't have a single local user on the channel. */
+  if (!silc_server_packet_relay_to_channel_encrypt(server, sender_sock,
+                                                  channel, data,
+                                                  data_len))
+    return;
+
   /* Set the packet context pointers. */
   packetdata.flags = 0;
   packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
   packetdata.src_id = silc_id_id2str(sender, sender_type);
-  packetdata.src_id_len = silc_id_get_len(sender_type);
+  packetdata.src_id_len = silc_id_get_len(sender, sender_type);
   packetdata.src_id_type = sender_type;
   packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
-
-  /* This encrypts the packet, if needed. It will be encrypted if
-     it came from the router thus it needs to be encrypted with the
-     channel key. If the channel key does not exist, then we know we
-     don't have a single local user on the channel. */
-  silc_server_packet_relay_to_channel_encrypt(server, sender_sock,
-                                             channel, data,
-                                             data_len);
 
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
-  if (server->server_type == SILC_SERVER && !server->standalone &&
+  if (server->server_type != SILC_ROUTER && !server->standalone &&
       channel->global_users) {
-    SilcServerEntry router;
-
-    router = server->router;
+    SilcServerEntry router = server->router;
 
     /* Check that the sender is not our router. */
     if (sender_sock != (SilcSocketConnection)router->connection) {
@@ -648,147 +788,164 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++, 
                                              data, data_len, TRUE, 
                                              force_send);
     }
   }
 
+  routed = silc_calloc(silc_hash_table_count(channel->user_list), 
+                      sizeof(*routed));
+
+  /* Mark that to the route the original sender if from is not routed */
+  if (sender_type == SILC_ID_CLIENT) {
+    client = (SilcClientEntry)sender_entry;
+    if (client->router) {
+      routed[routed_count++] = client->router;
+      SILC_LOG_DEBUG(("************* router %s", 
+                     silc_id_render(client->router->id, SILC_ID_SERVER)));
+    }
+  }
+
   /* Send the message to clients on the channel's client list. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+  silc_hash_table_list(channel->user_list, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     client = chl->client;
+    if (!client)
+      continue;
 
-    if (client) {
+    /* Do not send to the sender */
+    if (!found && client == sender_entry) {
+      found = TRUE;
+      continue;
+    }
 
-      /* If sender is one on the channel do not send it the packet. */
-      if (!found && sender_type == SILC_ID_CLIENT &&
-         !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
+    /* If the client has set router it means that it is not locally
+       connected client and we will route the packet further. */
+    if (server->server_type == SILC_ROUTER && client->router) {
+
+      /* Sender maybe server as well so we want to make sure that
+        we won't send the message to the server it came from. */
+      if (!found && SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
        found = TRUE;
+       routed[routed_count++] = client->router;
        continue;
       }
 
-      /* If the client has set router it means that it is not locally
-        connected client and we will route the packet further. */
-      if (server->server_type == SILC_ROUTER && client->router) {
-       int k;
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       continue;
+       
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)client->router->connection;
+      idata = (SilcIDListData)client->router;
 
-       /* Sender maybe server as well so we want to make sure that
-          we won't send the message to the server it came from. */
-       if (!found && !SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
-         found = TRUE;
-         continue;
-       }
+      /* Do not send to the sender. Check first whether the true
+        sender's router is same as this client's router. Also check
+        if the sender socket is the same as this client's router
+        socket. */
+      if (sender_entry &&
+         ((SilcClientEntry)sender_entry)->router == client->router)
+       continue;
+      if (sender_sock && sock == sender_sock)
+       continue;
 
-       /* Check if we have sent the packet to this route already */
-       for (k = 0; k < routed_count; k++)
-         if (routed[k] == client->router)
-           break;
-       if (k < routed_count)
-         continue;
+      SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)", 
+                     silc_id_render(client->id, SILC_ID_CLIENT),
+                     sock->hostname, sock->ip));
+
+      /* Mark this route routed already. */
+      routed[routed_count++] = client->router;
        
-       /* Get data used in packet header encryption, keys and stuff. */
-       sock = (SilcSocketConnection)client->router->connection;
-       idata = (SilcIDListData)client->router;
-
-       /* Do not send to the sender. Check first whether the true
-          sender's router is same as this client's router. Also check
-          if the sender socket is the same as this client's router
-          socket. */
-       if (sender_entry && 
-           ((SilcClientEntry)sender_entry)->router == client->router)
-         continue;
-       if (sender_sock && sock == sender_sock)
+      /* If the remote connection is router then we'll decrypt the
+        channel message and re-encrypt it with the session key shared
+        between us and the remote router. This is done because the
+        channel keys are cell specific and we have different channel
+        key than the remote router has. */
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
          continue;
 
-       SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)", 
-                       silc_id_render(client->id, SILC_ID_CLIENT),
-                       sock->hostname, sock->ip));
+       SILC_LOG_DEBUG(("Remote is router, encrypt with session key"));
+       gone = TRUE;
 
-       /* We want to make sure that the packet is routed to same router
-          only once. Mark this route as sent route. */
-       k = routed_count;
-       routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
-       routed[k] = client->router;
-       routed_count++;
-       
-       /* If the remote connection is router then we'll decrypt the
-          channel message and re-encrypt it with the session key shared
-          between us and the remote router. This is done because the
-          channel keys are cell specific and we have different channel
-          key than the remote router has. */
-       if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
-
-         /* If private key mode is not set then decrypt the packet
-            and re-encrypt it */
-         if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
-           unsigned char *tmp = silc_calloc(data_len, sizeof(*data));
-           memcpy(tmp, data, data_len);
-
-           /* Decrypt the channel message (we don't check the MAC) */
-           if (channel->channel_key &&
-               !silc_channel_message_payload_decrypt(tmp, data_len, 
-                                                     channel->channel_key,
-                                                     NULL)) {
-             memset(tmp, 0, data_len);
-             silc_free(tmp);
-             continue;
-           }
-
-           /* Now re-encrypt and send it to the router */
-           silc_server_packet_send_srcdest(server, sock, 
-                                           SILC_PACKET_CHANNEL_MESSAGE, 0,
-                                           sender, sender_type,
-                                           channel->id, SILC_ID_CHANNEL,
-                                           tmp, data_len, force_send);
-           
-           /* Free the copy of the channel message */
+       /* If private key mode is not set then decrypt the packet
+          and re-encrypt it */
+       if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+         unsigned char *tmp = silc_calloc(data_len, sizeof(*data));
+         memcpy(tmp, data, data_len);
+
+         /* Decrypt the channel message (we don't check the MAC) */
+         if (channel->channel_key &&
+             !silc_channel_message_payload_decrypt(tmp, data_len, 
+                                                   channel->channel_key,
+                                                   NULL)) {
            memset(tmp, 0, data_len);
            silc_free(tmp);
-         } else {
-           /* Private key mode is set, we don't have the channel key, so
-              just re-encrypt the entire packet and send it to the router. */
-           silc_server_packet_send_srcdest(server, sock, 
-                                           SILC_PACKET_CHANNEL_MESSAGE, 0,
-                                           sender, sender_type,
-                                           channel->id, SILC_ID_CHANNEL,
-                                           data, data_len, force_send);
+           continue;
          }
-         continue;
-       }
-
-       /* Send the packet (to normal server) */
-       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, 
-                                               idata->hmac_send, 
-                                               data, data_len, TRUE, 
-                                               force_send);
 
+         /* Now re-encrypt and send it to the router */
+         silc_server_packet_send_srcdest(server, sock, 
+                                         SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                         sender, sender_type,
+                                         channel->id, SILC_ID_CHANNEL,
+                                         tmp, data_len, force_send);
+
+         /* Free the copy of the channel message */
+         memset(tmp, 0, data_len);
+         silc_free(tmp);
+       } else {
+         /* Private key mode is set, we don't have the channel key, so
+            just re-encrypt the entire packet and send it to the router. */
+         silc_server_packet_send_srcdest(server, sock, 
+                                         SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                         sender, sender_type,
+                                         channel->id, SILC_ID_CHANNEL,
+                                         data, data_len, force_send);
+       }
        continue;
       }
 
-      if (client && client->router)
-       continue;
-
-      /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)client->connection;
-      idata = (SilcIDListData)client;
-
-      if (sender_sock && sock == sender_sock)
-       continue;
-
-      SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)", 
-                     silc_id_render(client->id, SILC_ID_CLIENT),
-                     sock->hostname, sock->ip));
-
-      /* Send the packet */
+      /* Send the packet (to normal server) */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
                                              idata->hmac_send, 
+                                             idata->psn_send++, 
                                              data, data_len, TRUE, 
                                              force_send);
+
+      continue;
     }
+
+    if (client->router)
+      continue;
+
+    /* Get data used in packet header encryption, keys and stuff. */
+    sock = (SilcSocketConnection)client->connection;
+    idata = (SilcIDListData)client;
+
+    if (sender_sock && sock == sender_sock)
+      continue;
+
+    SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)", 
+                   silc_id_render(client->id, SILC_ID_CLIENT),
+                   sock->hostname, sock->ip));
+
+    /* Send the packet */
+    silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                           idata->send_key, 
+                                           idata->hmac_send, 
+                                           idata->psn_send++, 
+                                           data, data_len, TRUE, 
+                                           force_send);
   }
 
+  silc_hash_table_list_reset(&htl);
+  silc_free(routed);
   silc_free(packetdata.src_id);
   silc_free(packetdata.dst_id);
 }
@@ -806,16 +963,17 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                           SilcPacketFlags flags,
                                           unsigned char *data,
                                           uint32 data_len,
-                                          int force_send)
+                                          bool force_send)
 {
   SilcChannelClientEntry chl;
+  SilcHashTableList htl;
   SilcSocketConnection sock = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Send the message to clients on the channel's client list. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+  silc_hash_table_list(channel->user_list, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     if (chl->client && !chl->client->router) {
       sock = (SilcSocketConnection)chl->client->connection;
 
@@ -825,6 +983,7 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                   force_send);
     }
   }
+  silc_hash_table_list_reset(&htl);
 }
 
 /* Routine used to send (relay, route) private messages to some destination.
@@ -837,21 +996,22 @@ void silc_server_send_private_message(SilcServer server,
                                      SilcSocketConnection dst_sock,
                                      SilcCipher cipher,
                                      SilcHmac hmac,
+                                     uint32 sequence,
                                      SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
 
   /* Re-encrypt and send if private messge key does not exist */
-  if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+  if (!(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY)) {
 
     silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
                     + packet->dst_id_len + packet->padlen);
     silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
     silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    
+
     /* Re-encrypt packet */
-    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
-    
+    silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, buffer->len);
+
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, FALSE);
 
@@ -863,7 +1023,7 @@ void silc_server_send_private_message(SilcServer server,
     silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
 
     /* Encrypt header */
-    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, 
+    silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, 
                        SILC_PACKET_HEADER_LEN + packet->src_id_len + 
                        packet->dst_id_len + packet->padlen);
 
@@ -876,13 +1036,14 @@ void silc_server_send_private_message(SilcServer server,
 void silc_server_send_motd(SilcServer server,
                           SilcSocketConnection sock)
 {
-  char *motd;
+  char *motd, *motd_file = NULL;
   uint32 motd_len;
 
-  if (server->config && server->config->motd && 
-      server->config->motd->motd_file) {
+  if (server->config)
+    motd_file = server->config->server_info->motd_file;
 
-    motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+  if (motd_file) {
+    motd = silc_file_readfile(motd_file, &motd_len);
     if (!motd)
       return;
 
@@ -918,7 +1079,7 @@ void silc_server_send_error(SilcServer server,
 
 void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
-                            int broadcast,
+                            bool broadcast,
                             SilcNotifyType type,
                             uint32 argc, ...)
 {
@@ -931,7 +1092,16 @@ void silc_server_send_notify(SilcServer server,
   silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          packet->data, packet->len, FALSE);
+
+  /* Send to backup routers if this is being broadcasted to primary
+     router. */
+  if (server->router && server->router->connection &&
+      sock == server->router->connection && broadcast)
+    silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0,
+                           packet->data, packet->len, FALSE, TRUE);
+
   silc_buffer_free(packet);
+  va_end(ap);
 }
 
 /* Sends notify message and gets the arguments from the `args' Argument
@@ -939,7 +1109,7 @@ void silc_server_send_notify(SilcServer server,
 
 void silc_server_send_notify_args(SilcServer server,
                                  SilcSocketConnection sock,
-                                 int broadcast,
+                                 bool broadcast,
                                  SilcNotifyType type,
                                  uint32 argc,
                                  SilcBuffer args)
@@ -958,10 +1128,9 @@ void silc_server_send_notify_args(SilcServer server,
 
 void silc_server_send_notify_channel_change(SilcServer server,
                                            SilcSocketConnection sock,
-                                           int broadcast,
+                                           bool broadcast,
                                            SilcChannelID *old_id,
-                                           SilcChannelID *new_id,
-                                           uint32 id_len)
+                                           SilcChannelID *new_id)
 {
   SilcBuffer idp1, idp2;
 
@@ -980,10 +1149,9 @@ void silc_server_send_notify_channel_change(SilcServer server,
 
 void silc_server_send_notify_nick_change(SilcServer server,
                                         SilcSocketConnection sock,
-                                        int broadcast,
+                                        bool broadcast,
                                         SilcClientID *old_id,
-                                        SilcClientID *new_id,
-                                        uint32 id_len)
+                                        SilcClientID *new_id)
 {
   SilcBuffer idp1, idp2;
 
@@ -1002,10 +1170,9 @@ void silc_server_send_notify_nick_change(SilcServer server,
 
 void silc_server_send_notify_join(SilcServer server,
                                  SilcSocketConnection sock,
-                                 int broadcast,
+                                 bool broadcast,
                                  SilcChannelEntry channel,
-                                 SilcClientID *client_id,
-                                 uint32 client_id_len)
+                                 SilcClientID *client_id)
 {
   SilcBuffer idp1, idp2;
 
@@ -1023,10 +1190,9 @@ void silc_server_send_notify_join(SilcServer server,
 
 void silc_server_send_notify_leave(SilcServer server,
                                   SilcSocketConnection sock,
-                                  int broadcast,
+                                  bool broadcast,
                                   SilcChannelEntry channel,
-                                  SilcClientID *client_id,
-                                  uint32 client_id_len)
+                                  SilcClientID *client_id)
 {
   SilcBuffer idp;
 
@@ -1043,12 +1209,12 @@ void silc_server_send_notify_leave(SilcServer server,
 
 void silc_server_send_notify_cmode(SilcServer server,
                                   SilcSocketConnection sock,
-                                  int broadcast,
+                                  bool broadcast,
                                   SilcChannelEntry channel,
                                   uint32 mode_mask,
                                   void *id, SilcIdType id_type,
-                                  uint32 id_len,
-                                  char *cipher, char *hmac)
+                                  char *cipher, char *hmac,
+                                  char *passphrase)
 {
   SilcBuffer idp;
   unsigned char mode[4];
@@ -1058,31 +1224,31 @@ void silc_server_send_notify_cmode(SilcServer server,
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              4, idp->data, idp->len,
+                              5, idp->data, idp->len,
                               mode, 4,
                               cipher, cipher ? strlen(cipher) : 0,
-                              hmac, hmac ? strlen(hmac) : 0);
+                              hmac, hmac ? strlen(hmac) : 0,
+                              passphrase, passphrase ? 
+                              strlen(passphrase) : 0);
   silc_buffer_free(idp);
 }
 
 /* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
-   `target' client's mode on `channel'. The Notify packet is always
+   `target' client's mode on `channel'. The notify packet is always
    destined to the channel. */
 
 void silc_server_send_notify_cumode(SilcServer server,
                                    SilcSocketConnection sock,
-                                   int broadcast,
+                                   bool broadcast,
                                    SilcChannelEntry channel,
                                    uint32 mode_mask,
-                                   SilcClientID *client_id,
-                                   uint32 client_id_len,
-                                   SilcClientID *target,
-                                   uint32 target_len)
+                                   void *id, SilcIdType id_type,
+                                   SilcClientID *target)
 {
   SilcBuffer idp1, idp2;
   unsigned char mode[4];
 
-  idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp1 = silc_id_payload_encode((void *)id, id_type);
   idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
   SILC_PUT32_MSB(mode_mask, mode);
 
@@ -1103,10 +1269,9 @@ void silc_server_send_notify_cumode(SilcServer server,
 
 void silc_server_send_notify_signoff(SilcServer server,
                                     SilcSocketConnection sock,
-                                    int broadcast,
+                                    bool broadcast,
                                     SilcClientID *client_id,
-                                    uint32 client_id_len,
-                                    char *message)
+                                    const char *message)
 {
   SilcBuffer idp;
 
@@ -1118,27 +1283,27 @@ void silc_server_send_notify_signoff(SilcServer server,
   silc_buffer_free(idp);
 }
 
-/* Sends TOPIC_SET notify type. This tells that `client_id' changed
+/* Sends TOPIC_SET notify type. This tells that `id' changed
    the `channel's topic to `topic'. The Notify packet is always destined
    to the channel. This function is used to send the topic set notifies
    between routers. */
 
 void silc_server_send_notify_topic_set(SilcServer server,
                                       SilcSocketConnection sock,
-                                      int broadcast,
+                                      bool broadcast,
                                       SilcChannelEntry channel,
-                                      SilcClientID *client_id,
-                                      uint32 client_id_len,
+                                      void *id, SilcIdType id_type,
                                       char *topic)
 {
   SilcBuffer idp;
 
-  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
-  silc_server_send_notify(server, sock, broadcast,
-                         SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
-                         topic ? 2 : 1, 
-                         idp->data, idp->len, 
-                         topic, topic ? strlen(topic) : 0);
+  idp = silc_id_payload_encode(id, id_type);
+  silc_server_send_notify_dest(server, sock, broadcast,
+                              (void *)channel->id, SILC_ID_CHANNEL,
+                              SILC_NOTIFY_TYPE_TOPIC_SET,
+                              topic ? 2 : 1, 
+                              idp->data, idp->len, 
+                              topic, topic ? strlen(topic) : 0);
   silc_buffer_free(idp);
 }
 
@@ -1149,20 +1314,24 @@ void silc_server_send_notify_topic_set(SilcServer server,
 
 void silc_server_send_notify_kicked(SilcServer server,
                                    SilcSocketConnection sock,
-                                   int broadcast,
+                                   bool broadcast,
                                    SilcChannelEntry channel,
                                    SilcClientID *client_id,
-                                   uint32 client_id_len,
+                                   SilcClientID *kicker,
                                    char *comment)
 {
-  SilcBuffer idp;
+  SilcBuffer idp1;
+  SilcBuffer idp2;
 
-  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  idp2 = silc_id_payload_encode((void *)kicker, SILC_ID_CLIENT);
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
-                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED,
-                              comment ? 2 : 1, idp->data, idp->len,
-                              comment, comment ? strlen(comment) : 0);
-  silc_buffer_free(idp);
+                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED, 3,
+                              idp1->data, idp1->len,
+                              comment, comment ? strlen(comment) : 0,
+                              idp2->data, idp2->len);
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
 }
 
 /* Send KILLED notify type. This tells that the `client_id' client was
@@ -1171,9 +1340,8 @@ void silc_server_send_notify_kicked(SilcServer server,
 
 void silc_server_send_notify_killed(SilcServer server,
                                    SilcSocketConnection sock,
-                                   int broadcast,
+                                   bool broadcast,
                                    SilcClientID *client_id,
-                                   uint32 client_id_len,
                                    char *comment)
 {
   SilcBuffer idp;
@@ -1192,9 +1360,8 @@ void silc_server_send_notify_killed(SilcServer server,
 
 void silc_server_send_notify_umode(SilcServer server,
                                   SilcSocketConnection sock,
-                                  int broadcast,
+                                  bool broadcast,
                                   SilcClientID *client_id,
-                                  uint32 client_id_len,
                                   uint32 mode_mask)
 {
   SilcBuffer idp;
@@ -1216,7 +1383,7 @@ void silc_server_send_notify_umode(SilcServer server,
 
 void silc_server_send_notify_ban(SilcServer server,
                                 SilcSocketConnection sock,
-                                int broadcast,
+                                bool broadcast,
                                 SilcChannelEntry channel,
                                 char *add, char *del)
 {
@@ -1238,10 +1405,9 @@ void silc_server_send_notify_ban(SilcServer server,
 
 void silc_server_send_notify_invite(SilcServer server,
                                    SilcSocketConnection sock,
-                                   int broadcast,
+                                   bool broadcast,
                                    SilcChannelEntry channel,
                                    SilcClientID *client_id,
-                                   uint32 client_id_len,
                                    char *add, char *del)
 {
   SilcBuffer idp, idp2;
@@ -1263,7 +1429,7 @@ void silc_server_send_notify_invite(SilcServer server,
 
 void silc_server_send_notify_dest(SilcServer server,
                                  SilcSocketConnection sock,
-                                 int broadcast,
+                                 bool broadcast,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
@@ -1275,10 +1441,12 @@ void silc_server_send_notify_dest(SilcServer server,
   va_start(ap, argc);
 
   packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, 
+  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 
+                              broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                               dest_id, dest_id_type,
                               packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
+  va_end(ap);
 }
 
 /* Sends notify message to a channel. The notify message sent is 
@@ -1291,7 +1459,7 @@ void silc_server_send_notify_dest(SilcServer server,
 void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
-                                       unsigned char route_notify,
+                                       bool route_notify,
                                        SilcNotifyType type,
                                        uint32 argc, ...)
 {
@@ -1305,6 +1473,7 @@ void silc_server_send_notify_to_channel(SilcServer server,
                                     SILC_PACKET_NOTIFY, route_notify,
                                     packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
+  va_end(ap);
 }
 
 /* Send notify message to all channels the client has joined. It is quaranteed
@@ -1328,18 +1497,19 @@ void silc_server_send_notify_on_channels(SilcServer server,
   uint32 sent_clients_count = 0;
   SilcServerEntry *routed = NULL;
   uint32 routed_count = 0;
+  SilcHashTableList htl, htl2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl, chl2;
   SilcIDListData idata;
   SilcBuffer packet;
   unsigned char *data;
   uint32 data_len;
-  int force_send = FALSE;
+  bool force_send = FALSE;
   va_list ap;
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (!silc_list_count(client->channels))
+  if (!silc_hash_table_count(client->channels))
     return;
 
   va_start(ap, argc);
@@ -1351,16 +1521,16 @@ void silc_server_send_notify_on_channels(SilcServer server,
   packetdata.flags = 0;
   packetdata.type = SILC_PACKET_NOTIFY;
   packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
-  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
   packetdata.src_id_type = SILC_ID_SERVER;
 
-  silc_list_start(client->channels);
-  while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
+  silc_hash_table_list(client->channels, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     channel = chl->channel;
 
     /* Send the message to all clients on the channel's client list. */
-    silc_list_start(channel->user_list);
-    while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    silc_hash_table_list(channel->user_list, &htl2);
+    while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
       c = chl2->client;
       
       if (sender && c == sender)
@@ -1387,18 +1557,24 @@ void silc_server_send_notify_on_channels(SilcServer server,
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)c->router->connection;
        idata = (SilcIDListData)c->router;
-       
+
+       {
+         SILC_LOG_DEBUG(("*****************"));
+         SILC_LOG_DEBUG(("client->router->id %s",
+                         silc_id_render(c->router->id, SILC_ID_SERVER)));
+         SILC_LOG_DEBUG(("client->router->connection->user_data->id %s",
+                         silc_id_render(((SilcServerEntry)sock->user_data)->id, SILC_ID_SERVER)));
+       }
+
        packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
-       packetdata.dst_id_len = SILC_ID_SERVER_LEN;
+       packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER);
        packetdata.dst_id_type = SILC_ID_SERVER;
-       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-         packetdata.src_id_len + packetdata.dst_id_len;
-       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                                idata->send_key, 
                                                idata->hmac_send, 
+                                               idata->psn_send++, 
                                                data, data_len, FALSE, 
                                                force_send);
        
@@ -1406,11 +1582,8 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
        /* We want to make sure that the packet is routed to same router
           only once. Mark this route as sent route. */
-       k = routed_count;
-       routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
-       routed[k] = c->router;
-       routed_count++;
-
+       routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+       routed[routed_count++] = c->router;
        continue;
       }
 
@@ -1425,16 +1598,14 @@ void silc_server_send_notify_on_channels(SilcServer server,
        idata = (SilcIDListData)c;
        
        packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
-       packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+       packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
        packetdata.dst_id_type = SILC_ID_CLIENT;
-       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-         packetdata.src_id_len + packetdata.dst_id_len;
-       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                                idata->send_key, 
                                                idata->hmac_send, 
+                                               idata->psn_send++, 
                                                data, data_len, FALSE, 
                                                force_send);
 
@@ -1443,17 +1614,18 @@ void silc_server_send_notify_on_channels(SilcServer server,
        /* Make sure that we send the notify only once per client. */
        sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) * 
                                    (sent_clients_count + 1));
-       sent_clients[sent_clients_count] = c;
-       sent_clients_count++;
+       sent_clients[sent_clients_count++] = c;
       }
     }
+    silc_hash_table_list_reset(&htl2);
   }
 
-  if (routed_count)
-    silc_free(routed);
-  if (sent_clients_count)
-    silc_free(sent_clients);
+  silc_hash_table_list_reset(&htl);
+  silc_free(routed);
+  silc_free(sent_clients);
   silc_free(packetdata.src_id);
+  silc_buffer_free(packet);
+  va_end(ap);
 }
 
 /* Sends New ID Payload to remote end. The packet is used to distribute
@@ -1464,7 +1636,7 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
 void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
-                            int broadcast,
+                            bool broadcast,
                             void *id, SilcIdType id_type, 
                             uint32 id_len)
 {
@@ -1476,17 +1648,24 @@ void silc_server_send_new_id(SilcServer server,
   silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
                          idp->data, idp->len, FALSE);
+
+  /* Send to backup routers if this is being broadcasted to primary
+     router. */
+  if (server->router && server->router->connection &&
+      sock == server->router->connection && broadcast)
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+                           idp->data, idp->len, FALSE, TRUE);
+
   silc_buffer_free(idp);
 }
 
 /* Send New Channel Payload to notify about newly created channel in the
-   SILC network. Normal server nevers sends this packet. Router uses this
-   to notify other routers in the network about new channel. This packet
-   is broadcasted. */
+   SILC network. Router uses this to notify other routers in the network 
+   about new channel. This packet is broadcasted by router. */
 
 void silc_server_send_new_channel(SilcServer server,
                                  SilcSocketConnection sock,
-                                 int broadcast,
+                                 bool broadcast,
                                  char *channel_name,
                                  void *channel_id, 
                                  uint32 channel_id_len,
@@ -1510,6 +1689,14 @@ void silc_server_send_new_channel(SilcServer server,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
                          packet->data, packet->len, FALSE);
 
+  /* Send to backup routers if this is being broadcasted to primary
+     router. */
+  if (server->server_type == SILC_ROUTER &&
+      server->router && server->router->connection &&
+      sock == server->router->connection && broadcast)
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
+                           packet->data, packet->len, FALSE, TRUE);
+
   silc_free(cid);
   silc_buffer_free(packet);
 }
@@ -1532,7 +1719,7 @@ void silc_server_send_channel_key(SilcServer server,
   unsigned char *chid;
   uint32 tmp_len;
  
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name));
  
   chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   if (!chid)
@@ -1540,13 +1727,15 @@ void silc_server_send_channel_key(SilcServer server,
  
   /* Encode channel key packet */
   tmp_len = strlen(channel->channel_key->cipher->name);
-  packet = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, chid, tmp_len,
+  packet = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
+                                                          SILC_ID_CHANNEL),
+                                          chid, tmp_len,
                                            channel->channel_key->cipher->name,
                                            channel->key_len / 8, channel->key);
   silc_server_packet_send_to_channel(server, sender, channel, 
                                     SILC_PACKET_CHANNEL_KEY,
-                                     route, packet->data, packet->len, FALSE);
+                                     route, packet->data, packet->len, 
+                                    FALSE);
   silc_buffer_free(packet);
   silc_free(chid);
 }
@@ -1557,6 +1746,7 @@ void silc_server_send_channel_key(SilcServer server,
 void silc_server_send_command(SilcServer server, 
                              SilcSocketConnection sock,
                              SilcCommand command, 
+                             uint16 ident,
                              uint32 argc, ...)
 {
   SilcBuffer packet;
@@ -1564,10 +1754,60 @@ void silc_server_send_command(SilcServer server,
 
   va_start(ap, argc);
 
-  packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+  packet = silc_command_payload_encode_vap(command, ident, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
                          packet->data, packet->len, TRUE);
   silc_buffer_free(packet);
+  va_end(ap);
+}
+
+/* Generic function to send any command reply. The arguments must be sent
+   already encoded into correct form in correct order. */
+
+void silc_server_send_command_reply(SilcServer server, 
+                                   SilcSocketConnection sock,
+                                   SilcCommand command, 
+                                   SilcCommandStatus status,
+                                   uint16 ident,
+                                   uint32 argc, ...)
+{
+  SilcBuffer packet;
+  va_list ap;
+
+  va_start(ap, argc);
+
+  packet = silc_command_reply_payload_encode_vap(command, status, ident, 
+                                                argc, ap);
+  silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+                         packet->data, packet->len, TRUE);
+  silc_buffer_free(packet);
+  va_end(ap);
+}
+
+/* Generic function to send any command reply. The arguments must be sent
+   already encoded into correct form in correct order. */
+
+void silc_server_send_dest_command_reply(SilcServer server, 
+                                        SilcSocketConnection sock,
+                                        void *dst_id,
+                                        SilcIdType dst_id_type,
+                                        SilcCommand command, 
+                                        SilcCommandStatus status,
+                                        uint16 ident,
+                                        uint32 argc, ...)
+{
+  SilcBuffer packet;
+  va_list ap;
+
+  va_start(ap, argc);
+
+  packet = silc_command_reply_payload_encode_vap(command, status, ident, 
+                                                argc, ap);
+  silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+                              dst_id, dst_id_type, packet->data, 
+                              packet->len, TRUE);
+  silc_buffer_free(packet);
+  va_end(ap);
 }
 
 /* Send the heartbeat packet. */
@@ -1586,8 +1826,9 @@ void silc_server_relay_packet(SilcServer server,
                              SilcSocketConnection dst_sock,
                              SilcCipher cipher,
                              SilcHmac hmac,
+                             uint32 sequence,
                              SilcPacketContext *packet,
-                             int force_send)
+                             bool force_send)
 {
   silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
                   + packet->dst_id_len + packet->padlen);
@@ -1596,7 +1837,8 @@ void silc_server_relay_packet(SilcServer server,
   silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
   
   /* Re-encrypt packet */
-  silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len);
+  silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, 
+                     packet->buffer->len);
   
   /* Send the packet */
   silc_server_packet_send_real(server, dst_sock, force_send);
@@ -1625,3 +1867,25 @@ void silc_server_send_connection_auth_request(SilcServer server,
                          0, packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 }
+
+/* Purge the outgoing packet queue to the network if there is data. This
+   function can be used to empty the packet queue. It is guaranteed that
+   after this function returns the outgoing data queue is empty. */
+
+void silc_server_packet_queue_purge(SilcServer server,
+                                   SilcSocketConnection sock)
+{
+  if (sock && SILC_IS_OUTBUF_PENDING(sock) && 
+      (SILC_IS_DISCONNECTED(sock) == FALSE)) {
+    server->stat.packets_sent++;
+
+    if (sock->outbuf->data - sock->outbuf->head)
+      silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
+
+    silc_packet_send(sock, TRUE);
+
+    SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
+    SILC_UNSET_OUTBUF_PENDING(sock);
+    silc_buffer_clear(sock->outbuf);
+  }
+}