+ int i;
+
+ /*
+ * Most messages cause SSH2_MSG_UNIMPLEMENTED.
+ */
+ for (i = 0; i < 256; i++)
+ ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented;
+
+ /*
+ * Any message we actually understand, we set to NULL so that
+ * the coroutines will get it.
+ */
+ ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_KEXINIT] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_KEXDH_REPLY] = NULL;
+ /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REQUEST] = NULL; duplicate case value */
+ /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_GROUP] = NULL; duplicate case value */
+ ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = NULL;
+ /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = NULL; duplicate case value */
+ /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = NULL; duplicate case value */
+ ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = NULL;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = NULL;
+
+ /*
+ * These special message types we install handlers for.
+ */
+ ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect;
+ ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; /* shared with ssh1 */
+ ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;
+}
+
+static void ssh2_timer(void *ctx, long now)
+{
+ Ssh ssh = (Ssh)ctx;
+
+ if (!ssh->kex_in_progress &&
+ now - ssh->next_rekey >= 0) {
+ do_ssh2_transport(ssh, "Initiating key re-exchange (timeout)",
+ -1, NULL);
+ }
+}
+
+static void ssh2_protocol(Ssh ssh, unsigned char *in, int inlen,
+ struct Packet *pktin)
+{
+ if (ssh->state == SSH_STATE_CLOSED)
+ return;
+
+ if (pktin) {
+ ssh->incoming_data_size += pktin->encrypted_len;
+ if (!ssh->kex_in_progress &&
+ ssh->incoming_data_size > MAX_DATA_BEFORE_REKEY)
+ do_ssh2_transport(ssh, "Initiating key re-exchange "
+ "(too much data received)", -1, NULL);
+ }
+
+ if (pktin && ssh->packet_dispatch[pktin->type]) {
+ ssh->packet_dispatch[pktin->type](ssh, pktin);