-void silc_server_packet_send_to_channel(SilcServer server,
- SilcChannelList *channel,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- int i;
- SilcSocketConnection sock = NULL;
- SilcPacketContext packetdata;
- SilcClientList *client = NULL;
- SilcServerList **routed = NULL;
- unsigned int routed_count = 0;
- unsigned char *hmac_key = NULL;
- unsigned int hmac_key_len = 0;
- unsigned char mac[32];
- unsigned int mac_len = 0;
- SilcCipher cipher;
- SilcHmac hmac;
- SilcBuffer payload;
-
- SILC_LOG_DEBUG(("Sending packet to channel"));
-
- /* Generate IV */
- for (i = 0; i < 16; i++)
- channel->iv[i] = silc_rng_get_byte(server->rng);
-
- /* Encode the channel payload */
- payload = silc_channel_encode_payload(0, "", data_len, data,
- 16, channel->iv, server->rng);
- if (!payload)
- return;
-
- /* Encrypt payload of the packet. This is encrypted with the
- channel key. */
- channel->channel_key->cipher->encrypt(channel->channel_key->context,
- payload->data, payload->data,
- payload->len - 16, /* -IV_LEN */
- channel->iv);
-
- /* Set the packet context pointers. */
- packetdata.flags = 0;
- packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
- packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
- packetdata.src_id_len = SILC_ID_SERVER_LEN;
- 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_type = SILC_ID_CHANNEL;
- packetdata.rng = server->rng;
- packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_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 &&
- channel->global_users) {
- SilcServerList *router;
-
- /* Get data used in packet header encryption, keys and stuff. */
- router = server->id_entry->router;
- sock = (SilcSocketConnection)router->connection;
- cipher = router->send_key;
- hmac = router->hmac;
- mac_len = hmac->hash->hash->hash_len;
- hmac_key = router->hmac_key;
- hmac_key_len = router->hmac_key_len;
-
- SILC_LOG_DEBUG(("Sending packet to router for routing"));
-
- packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len;
-
- /* Prepare outgoing data buffer for packet sending */
- silc_server_packet_send_prepare(server, sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- payload->len);
- packetdata.buffer = sock->outbuf;
-
- /* Put the original packet into the buffer. */
- silc_buffer_put(sock->outbuf, payload->data, payload->len);
-
- /* Create the outgoing packet */
- silc_packet_assemble(&packetdata);
-
- /* Compute MAC of the packet. MAC is computed from the header,
- padding and the relayed packet. */
- silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
- hmac_key, hmac_key_len, mac);
- silc_buffer_put_tail(sock->outbuf, mac, mac_len);
- memset(mac, 0, sizeof(mac));
-
- /* Encrypt the header and padding of the packet. This is encrypted
- with normal session key shared with the client. */
- silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len +
- packetdata.padlen);
-
- /* Pull MAC into the visible data area */
- silc_buffer_pull_tail(sock->outbuf, mac_len);
-
- SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);