IKEv1: packet retransmit fixes for Main/Aggr/Xauth modes

- Do not schedule retransmits for inI1outR1 packets (prevent DDOS)
- Do schedule retransmits for XAUTH packets
void process_v1_packet(struct msg_digest **mdp)
{
	struct msg_digest *md = *mdp;
	const struct state_microcode *smc;
	bool new_iv_set = FALSE;
	struct state *st = NULL;
	enum state_kind from_state = STATE_UNDEFINED;   /* state we started in */

#define SEND_NOTIFICATION(t) { \
		if (st != NULL) \
			send_notification_from_state(st, from_state, t); \
		else \
			send_notification_from_md(md, t); }

	switch (md->hdr.isa_xchg) {
#ifdef NOTYET
	case ISAKMP_XCHG_NONE:
	case ISAKMP_XCHG_BASE:
	case ISAKMP_XCHG_AO:
#endif

	case ISAKMP_XCHG_AGGR:
	case ISAKMP_XCHG_IDPROT: /* part of a Main Mode exchange */
		if (md->hdr.isa_msgid != v1_MAINMODE_MSGID) {
			libreswan_log(
				"Message ID was 0x%08lx but should be zero in phase 1",
				(unsigned long) md->hdr.isa_msgid);
			SEND_NOTIFICATION(INVALID_MESSAGE_ID);
			return;
		}

		if (is_zero_cookie(md->hdr.isa_icookie)) {
			libreswan_log(
				"Initiator Cookie must not be zero in phase 1 message");
			SEND_NOTIFICATION(INVALID_COOKIE);
			return;
		}

		if (is_zero_cookie(md->hdr.isa_rcookie)) {
			/* initial message from initiator
			 * ??? what if this is a duplicate of another message?
			 */
			if (md->hdr.isa_flags & ISAKMP_FLAGS_v1_ENCRYPTION) {
				libreswan_log("initial phase 1 message is invalid:"
					      " its Encrypted Flag is on");
				SEND_NOTIFICATION(INVALID_FLAGS);
				return;
			}

			/* don't build a state until the message looks tasty */
			from_state = (md->hdr.isa_xchg == ISAKMP_XCHG_IDPROT ?
				      STATE_MAIN_R0 : STATE_AGGR_R0);
		} else {
			/* not an initial message */

			st = find_state_ikev1(md->hdr.isa_icookie,
					      md->hdr.isa_rcookie,
					      md->hdr.isa_msgid);

			if (st == NULL) {
				/* perhaps this is a first message from the responder
				 * and contains a responder cookie that we've not yet seen.
				 */
				st = find_state_ikev1(md->hdr.isa_icookie,
						      zero_cookie,
						      md->hdr.isa_msgid);

				if (st == NULL) {
					libreswan_log(
						"phase 1 message is part of an unknown exchange");
					/* XXX Could send notification back */
					return;
				}
			}
			set_cur_state(st);
			from_state = st->st_state;
		}
		break;

	case ISAKMP_XCHG_INFO:  /* an informational exchange */
		st = ikev1_find_info_state(md->hdr.isa_icookie, md->hdr.isa_rcookie,
				     &md->sender, v1_MAINMODE_MSGID);

		if (st == NULL) {
			/*
			 * might be an informational response to our first
			 * message, in which case, we don't know the rcookie yet.
			 */
			st = find_state_ikev1(md->hdr.isa_icookie, zero_cookie,
					      v1_MAINMODE_MSGID);
		}

		if (st != NULL)
			set_cur_state(st);

		if (md->hdr.isa_flags & ISAKMP_FLAGS_v1_ENCRYPTION) {
			bool quiet = (st == NULL ||
				     (st->st_connection->policy & POLICY_OPPORTUNISTIC));

			if (st == NULL) {
				DBG(DBG_CONTROL, DBG_log(
						"Informational Exchange is for an unknown (expired?) SA with MSGID:0x%08lx",
							(unsigned long)md->hdr.isa_msgid));

				/* Let's try to log some info about these to track them down */
				DBG(DBG_CONTROL, {
					    DBG_dump("- unknown SA's md->hdr.isa_icookie:",
						    md->hdr.isa_icookie,
						    COOKIE_SIZE);
					    DBG_dump("- unknown SA's md->hdr.isa_rcookie:",
						    md->hdr.isa_rcookie,
						    COOKIE_SIZE);
				    });

				/* XXX Could send notification back */
				return;
			}

			if (!IS_ISAKMP_ENCRYPTED(st->st_state)) {
				if (!quiet) {
					loglog(RC_LOG_SERIOUS, "encrypted Informational Exchange message is invalid because no key is known");
				}
				/* XXX Could send notification back */
				return;
			}

			if (md->hdr.isa_msgid == v1_MAINMODE_MSGID) {
				if (!quiet) {
					loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because it has a Message ID of 0");
				}
				/* XXX Could send notification back */
				return;
			}

			if (!unique_msgid(st, md->hdr.isa_msgid)) {
				if (!quiet) {
					loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because it has a previously used Message ID (0x%08lx)",
						(unsigned long)md->hdr.isa_msgid);
				}
				/* XXX Could send notification back */
				return;
			}
			st->st_msgid_reserved = FALSE;

			init_phase2_iv(st, &md->hdr.isa_msgid);
			new_iv_set = TRUE;

			from_state = STATE_INFO_PROTECTED;
		} else {
			if (st != NULL &&
			    IS_ISAKMP_AUTHENTICATED(st->st_state)) {
				if ((st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					loglog(RC_LOG_SERIOUS, "Informational Exchange message must be encrypted");
				}
				/* XXX Could send notification back */
				return;
			}
			from_state = STATE_INFO;
		}
		break;

	case ISAKMP_XCHG_QUICK: /* part of a Quick Mode exchange */

		if (is_zero_cookie(md->hdr.isa_icookie)) {
			DBG(DBG_CONTROL, DBG_log(
				"Quick Mode message is invalid because it has an Initiator Cookie of 0"));
			SEND_NOTIFICATION(INVALID_COOKIE);
			return;
		}

		if (is_zero_cookie(md->hdr.isa_rcookie)) {
			DBG(DBG_CONTROL, DBG_log(
				"Quick Mode message is invalid because it has a Responder Cookie of 0"));
			SEND_NOTIFICATION(INVALID_COOKIE);
			return;
		}

		if (md->hdr.isa_msgid == v1_MAINMODE_MSGID) {
			DBG(DBG_CONTROL, DBG_log(
				"Quick Mode message is invalid because it has a Message ID of 0"));
			SEND_NOTIFICATION(INVALID_MESSAGE_ID);
			return;
		}

		st = find_state_ikev1(md->hdr.isa_icookie, md->hdr.isa_rcookie,
				      md->hdr.isa_msgid);

		if (st == NULL) {
			/* No appropriate Quick Mode state.
			 * See if we have a Main Mode state.
			 * ??? what if this is a duplicate of another message?
			 */
			st = find_state_ikev1(md->hdr.isa_icookie,
					      md->hdr.isa_rcookie,
					      v1_MAINMODE_MSGID);

			if (st == NULL) {
				DBG(DBG_CONTROL, DBG_log(
					"Quick Mode message is for a non-existent (expired?) ISAKMP SA"));
				/* XXX Could send notification back */
				return;
			}

			if (st->st_oakley.doing_xauth) {
				DBG(DBG_CONTROL, DBG_log(
					"Cannot do Quick Mode until XAUTH done."));
				return;
			}

			/* Have we just given an IP address to peer? */
			if (st->st_state == STATE_MODE_CFG_R2) {
				/* ISAKMP is up... */
				change_state(st, STATE_MAIN_R3);
			}

#ifdef SOFTREMOTE_CLIENT_WORKAROUND
			/* See: http://popoludnica.pl/?id=10100110 */
			if (st->st_state == STATE_MODE_CFG_R1) {
				libreswan_log(
					"SoftRemote workaround: Cannot do Quick Mode until MODECFG done.");
				return;
			}
#endif

			set_cur_state(st);

			if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {
				if (DBGP(DBG_OPPO) || (st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because it is for an incomplete ISAKMP SA");
				}
				SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
				return;
			}

			if (!unique_msgid(st, md->hdr.isa_msgid)) {
				if (DBGP(DBG_OPPO) || (st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					loglog(RC_LOG_SERIOUS, "Quick Mode I1 message is unacceptable because it uses a previously used Message ID 0x%08lx (perhaps this is a duplicated packet)",
						(unsigned long) md->hdr.isa_msgid);
				}
				SEND_NOTIFICATION(INVALID_MESSAGE_ID);
				return;
			}
			st->st_msgid_reserved = FALSE;

			/* Quick Mode Initial IV */
			init_phase2_iv(st, &md->hdr.isa_msgid);
			new_iv_set = TRUE;

			from_state = STATE_QUICK_R0;
		} else {
			if (st->st_oakley.doing_xauth) {
				if (DBGP(DBG_OPPO) ||
				    (st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					libreswan_log("Cannot do Quick Mode until XAUTH done.");
				}
				return;
			}
			set_cur_state(st);
			from_state = st->st_state;
		}

		break;

	case ISAKMP_XCHG_MODE_CFG:
		if (is_zero_cookie(md->hdr.isa_icookie)) {
			DBG(DBG_CONTROL, DBG_log("Mode Config message is invalid because it has an Initiator Cookie of 0"));
			/* XXX Could send notification back */
			return;
		}

		if (is_zero_cookie(md->hdr.isa_rcookie)) {
			DBG(DBG_CONTROL, DBG_log("Mode Config message is invalid because it has a Responder Cookie of 0"));
			/* XXX Could send notification back */
			return;
		}

		if (md->hdr.isa_msgid == 0) {
			DBG(DBG_CONTROL, DBG_log("Mode Config message is invalid because it has a Message ID of 0"));
			/* XXX Could send notification back */
			return;
		}

		st = ikev1_find_info_state(md->hdr.isa_icookie, md->hdr.isa_rcookie,
				     &md->sender, md->hdr.isa_msgid);

		if (st == NULL) {
			DBG(DBG_CONTROL, DBG_log(
				"No appropriate Mode Config state yet.See if we have a Main Mode state"));
			/* No appropriate Mode Config state.
			 * See if we have a Main Mode state.
			 * ??? what if this is a duplicate of another message?
			 */
			st = ikev1_find_info_state(md->hdr.isa_icookie,
					     md->hdr.isa_rcookie,
					     &md->sender, 0);

			if (st == NULL) {
				DBG(DBG_CONTROL, DBG_log(
					"Mode Config message is for a non-existent (expired?) ISAKMP SA"));
				/* XXX Could send notification back */
				return;
			}

			set_cur_state(st);

			DBG(DBG_CONTROLMORE, DBG_log(" processing received "
						     "isakmp_xchg_type %s.",
						     enum_show(&ikev1_exchange_names,
							       md->hdr.isa_xchg)));
			DBG(DBG_CONTROLMORE, DBG_log(" this is a%s%s%s%s",
						     st->st_connection->spd.
						     this.xauth_server ?
						     " xauthserver" : "",
						     st->st_connection->spd.
						     this.xauth_client ?
						     " xauthclient" : "",
						     st->st_connection->spd.
						     this.modecfg_server ?
						     " modecfgserver" : "",
						     st->st_connection->spd.
						     this.modecfg_client  ?
						     " modecfgclient" : ""
						     ));

			if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {
				DBG(DBG_CONTROLMORE, DBG_log(
					"Mode Config message is unacceptable because it is for an incomplete ISAKMP SA (state=%s)",
				       enum_name(&state_names, st->st_state)));
				/* XXX Could send notification back */
				return;
			}
			DBG(DBG_CONTROLMORE, DBG_log(" call  init_phase2_iv"));
			init_phase2_iv(st, &md->hdr.isa_msgid);
			new_iv_set = TRUE;

			/*
			 * okay, now we have to figure out if we are receiving a bogus
			 * new message in an oustanding XAUTH server conversation
			 * (i.e. a reply to our challenge)
			 * (this occurs with some broken other implementations).
			 *
			 * or if receiving for the first time, an XAUTH challenge.
			 *
			 * or if we are getting a MODECFG request.
			 *
			 * we distinguish these states because we cannot both be an
			 * XAUTH server and client, and our policy tells us which
			 * one we are.
			 *
			 * to complicate further, it is normal to start a new msgid
			 * when going from one state to another, or when restarting
			 * the challenge.
			 *
			 */

			if (st->st_connection->spd.this.xauth_server &&
			    st->st_state == STATE_XAUTH_R1 &&
			    st->quirks.xauth_ack_msgid) {
				from_state = STATE_XAUTH_R1;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s state is STATE_XAUTH_R1 and quirks.xauth_ack_msgid is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.xauth_client
				   &&
				   IS_PHASE1(st->st_state)) {
				from_state = STATE_XAUTH_I0;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is xauthclient and IS_PHASE1() is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.xauth_client
				   &&
				   st->st_state == STATE_XAUTH_I1) {
				/*
				 * in this case, we got a new MODECFG message after I0, maybe
				 * because it wants to start over again.
				 */
				from_state = STATE_XAUTH_I0;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is xauthclient and state == STATE_XAUTH_I1",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.modecfg_server
				   &&
				   IS_PHASE1(st->st_state)) {
				from_state = STATE_MODE_CFG_R0;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is modecfgserver and IS_PHASE1() is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.modecfg_client
				   &&
				   IS_PHASE1(st->st_state)) {
				from_state = STATE_MODE_CFG_R1;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is modecfgclient and IS_PHASE1() is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else {
				DBG(DBG_CONTROLMORE, DBG_log(
					"received isakmp_xchg_type %s",
					    enum_show(&ikev1_exchange_names,
						      md->hdr.isa_xchg)));
				DBG(DBG_CONTROLMORE, DBG_log(
					"this is a%s%s%s%s in state %s. Reply with UNSUPPORTED_EXCHANGE_TYPE",
					    st->st_connection
					    ->spd.this.xauth_server ?
					    " xauthserver" : "",
					    st->st_connection
					    ->spd.this.xauth_client ?
					    " xauthclient" : "",
					    st->st_connection
					    ->spd.this.modecfg_server ?
					    " modecfgserver" :
					    "",
					    st->st_connection
					    ->spd.this.modecfg_client  ?
					    " modecfgclient" :
					    "",
					    enum_name(&
						      state_names,
						      st->st_state)
					    ));
				return;
			}
		} else {
			if (st->st_connection->spd.this.xauth_server &&
			    IS_PHASE1(st->st_state)) {
				/* Switch from Phase1 to Mode Config */
				DBG(DBG_CONTROL, DBG_log(
					"We were in phase 1, with no state, so we went to XAUTH_R0"));
				change_state(st, STATE_XAUTH_R0);
			}

			/* otherweise, this is fine, we continue in the state we are in */
			set_cur_state(st);
			from_state = st->st_state;
		}

		break;

	case ISAKMP_XCHG_NGRP:
	default:
		DBG(DBG_CONTROL, DBG_log("unsupported exchange type %s in message",
			      enum_show(&ikev1_exchange_names, md->hdr.isa_xchg)));
		SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE);
		return;
	}

	/* We have found a from_state, and perhaps a state object.
	 * If we need to build a new state object,
	 * we wait until the packet has been sanity checked.
	 */

	/* We don't support the Commit Flag.  It is such a bad feature.
	 * It isn't protected -- neither encrypted nor authenticated.
	 * A man in the middle turns it on, leading to DoS.
	 * We just ignore it, with a warning.
	 */
	if (md->hdr.isa_flags & ISAKMP_FLAGS_v1_COMMIT)
		DBG(DBG_CONTROL, DBG_log(
			"IKE message has the Commit Flag set but Pluto doesn't implement this feature due to security concerns; ignoring flag"));


	/* Handle IKE fragmentation payloads */
	if (md->hdr.isa_np == ISAKMP_NEXT_IKE_FRAGMENTATION) {
		struct isakmp_ikefrag fraghdr;
		struct ike_frag *ike_frag, **i;
		int last_frag_index = 0;  /* index of the last fragment */
		pb_stream frag_pbs;

		if (st == NULL) {
			DBG(DBG_CONTROL, DBG_log(
				"received IKE fragment, but have no state. Ignoring packet."));
			return;
		}

		if ((st->st_connection->policy & POLICY_IKE_FRAG_ALLOW) == 0) {
			DBG(DBG_CONTROL, DBG_log(
			       "discarding IKE fragment packet - fragmentation not allowed by local policy (ike_frag=no)"));
			return;
		}

		if (!in_struct(&fraghdr, &isakmp_ikefrag_desc,
			       &md->message_pbs, &frag_pbs) ||
		    pbs_room(&frag_pbs) != fraghdr.isafrag_length ||
		    fraghdr.isafrag_np != 0 ||
		    fraghdr.isafrag_number == 0 || fraghdr.isafrag_number >
		    16) {
			SEND_NOTIFICATION(PAYLOAD_MALFORMED);
			return;
		}

		DBG(DBG_CONTROL,
		    DBG_log("received IKE fragment id '%d', number '%u'%s",
			    fraghdr.isafrag_id,
			    fraghdr.isafrag_number,
			    (fraghdr.isafrag_flags == 1) ? "(last)" : ""));

		ike_frag = alloc_thing(struct ike_frag, "ike_frag");
		ike_frag->md = md;
		ike_frag->index = fraghdr.isafrag_number;
		ike_frag->last = (fraghdr.isafrag_flags & 1);
		ike_frag->size = pbs_left(&frag_pbs);
		ike_frag->data = frag_pbs.cur;

#if 0
/* is this ever hit? It was wrongly checking one byte instead of 4 bytes of marker */
		/* Strip non-ESP marker from first fragment */
		if (md->iface->ike_float && ike_frag->index == 1 &&
		    (ike_frag->size >= NON_ESP_MARKER_SIZE &&
		     memeq(non_ESP_marker, ike_frag->data,
			    NON_ESP_MARKER_SIZE))) {
			ike_frag->data += NON_ESP_MARKER_SIZE;
			ike_frag->size -= NON_ESP_MARKER_SIZE;
		}
#endif

		/* Add the fragment to the state */
		i = &st->ike_frags;
		for (;;) {
			if (ike_frag != NULL) {
				/* Still looking for a place to insert ike_frag */
				if (*i == NULL ||
				    (*i)->index > ike_frag->index) {
					ike_frag->next = *i;
					*i = ike_frag;
					ike_frag = NULL;
				} else if ((*i)->index == ike_frag->index) {
					/* Replace fragment with same index */
					struct ike_frag *old = *i;

					ike_frag->next = old->next;
					*i = ike_frag;
					release_md(old->md);
					pfree(old);
					ike_frag = NULL;
				}
			}

			if (*i == NULL)
				break;

			if ((*i)->last)
				last_frag_index = (*i)->index;

			i = &(*i)->next;
		}

		/* We have the last fragment, reassemble if complete */
		if (last_frag_index != 0) {
			size_t size = 0;
			int prev_index = 0;
			struct ike_frag *frag;

			for (frag = st->ike_frags; frag; frag = frag->next) {
				size += frag->size;
				if (frag->index != ++prev_index) {
					break; /* fragment list incomplete */
				} else if (frag->index == last_frag_index) {
					struct msg_digest *whole_md = alloc_md();
					u_int8_t *buffer = alloc_bytes(size,
								       "IKE fragments buffer");
					size_t offset = 0;

					whole_md->iface = frag->md->iface;
					whole_md->sender = frag->md->sender;
					whole_md->sender_port =
						frag->md->sender_port;

					/* Reassemble fragments in buffer */
					frag = st->ike_frags;
					while (frag != NULL &&
					       frag->index <= last_frag_index)
					{
						passert(offset + frag->size <=
							size);
						memcpy(buffer + offset,
						       frag->data, frag->size);
						offset += frag->size;
						frag = frag->next;
					}

					init_pbs(&whole_md->packet_pbs, buffer, size,
						 "packet");

					process_packet(&whole_md);
					release_any_md(&whole_md);
					release_fragments(st);
					/* optimize: if receiving fragments, immediately respond with fragments too */
					st->st_seen_fragments = TRUE;
					DBG(DBG_CONTROL, DBG_log(
						" updated IKE fragment state to respond using fragments without waiting for re-transmits"));
					break;
				}
			}
		}

		/* Don't release the md, taken care of by the ike_frag code */
		/* ??? I'm not sure -- DHR */
		*mdp = NULL;
		return;
	}

	/* Set smc to describe this state's properties.
	 * Look up the appropriate microcode based on state and
	 * possibly Oakley Auth type.
	 */
	passert(STATE_IKE_FLOOR <= from_state && from_state <= STATE_IKE_ROOF);
	smc = ike_microcode_index[from_state - STATE_IKE_FLOOR];

	if (st != NULL) {
		oakley_auth_t baseauth =
			xauth_calcbaseauth(st->st_oakley.auth);

		while (!LHAS(smc->flags, baseauth)) {
			smc++;
			passert(smc->state == from_state);
		}
	}

	if (state_busy(st))
		return;

	/* Detect and handle duplicated packets.
	 * This won't work for the initial packet of an exchange
	 * because we won't have a state object to remember it.
	 * If we are in a non-receiving state (terminal), and the preceding
	 * state did transmit, then the duplicate may indicate that that
	 * transmission wasn't received -- retransmit it.
	 * Otherwise, just discard it.
	 * ??? Notification packets are like exchanges -- I hope that
	 * they are idempotent!
	 */
	if (st != NULL &&
	    st->st_rpacket.ptr != NULL &&
	    st->st_rpacket.len == pbs_room(&md->packet_pbs) &&
	    memeq(st->st_rpacket.ptr, md->packet_pbs.start,
		   st->st_rpacket.len)) {
		if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE) {
			if (st->st_retransmit < MAXIMUM_v1_ACCEPTED_DUPLICATES) {
				st->st_retransmit++;
				loglog(RC_RETRANSMISSION,
				       "retransmitting in response to duplicate packet; already %s",
				       enum_name(&state_names, st->st_state));
				resend_ike_v1_msg(st,
						  "retransmit in response to duplicate");
			} else {
				loglog(RC_LOG_SERIOUS,
				       "discarding duplicate packet -- exhausted retransmission; already %s",
				       enum_name(&state_names, st->st_state));
			}
		} else {
			loglog(RC_LOG_SERIOUS,
			       "discarding duplicate packet; already %s",
			       enum_name(&state_names, st->st_state));
		}
		return;
	}

	/* save values for use in resumption of processing below.
	 * (may be suspended due to crypto operation not yet complete)
	 */
	md->st = st;
	md->from_state = from_state;
	md->smc = smc;
	md->new_iv_set = new_iv_set;

	/*
	 * look for encrypt packets. We cannot handle them if we have not
	 * yet calculated the skeyids. We will just store the packet in
	 * the suspended state, since the calculation is likely underway.
	 *
	 * note that this differs from above, because skeyid is calculated
	 * in between states. (or will be, once DH is async)
	 *
	 */
	if ((md->hdr.isa_flags & ISAKMP_FLAGS_v1_ENCRYPTION) &&
	    st != NULL && !st->hidden_variables.st_skeyid_calculated ) {
		DBG(DBG_CRYPT | DBG_CONTROL, {
			ipstr_buf b;
			DBG_log("received encrypted packet from %s:%u but exponentiation still in progress",
				ipstr(&md->sender, &b),
				(unsigned)md->sender_port);
		});

		/* if there was a previous packet, let it go, and go with most
		 * recent one.
		 */
		if (st->st_suspended_md != NULL) {
			DBG(DBG_CONTROL,
			    DBG_log("releasing suspended operation before completion: %p",
				    st->st_suspended_md));
			release_any_md(&st->st_suspended_md);
		}

		set_suspended(st, md);
		*mdp = NULL;
		return;
	}

	process_packet_tail(mdp);
	/* our caller will release_any_md(mdp); */
}

void process_v1_packet(struct msg_digest **mdp)
{
	struct msg_digest *md = *mdp;
	const struct state_microcode *smc;
	bool new_iv_set = FALSE;
	struct state *st = NULL;
	enum state_kind from_state = STATE_UNDEFINED;   /* state we started in */

#define SEND_NOTIFICATION(t) { \
		if (st != NULL) \
			send_notification_from_state(st, from_state, t); \
		else \
			send_notification_from_md(md, t); }

	switch (md->hdr.isa_xchg) {
#ifdef NOTYET
	case ISAKMP_XCHG_NONE:
	case ISAKMP_XCHG_BASE:
	case ISAKMP_XCHG_AO:
#endif

	case ISAKMP_XCHG_AGGR:
	case ISAKMP_XCHG_IDPROT: /* part of a Main Mode exchange */
		if (md->hdr.isa_msgid != v1_MAINMODE_MSGID) {
			libreswan_log(
				"Message ID was 0x%08lx but should be zero in phase 1",
				(unsigned long) md->hdr.isa_msgid);
			SEND_NOTIFICATION(INVALID_MESSAGE_ID);
			return;
		}

		if (is_zero_cookie(md->hdr.isa_icookie)) {
			libreswan_log(
				"Initiator Cookie must not be zero in phase 1 message");
			SEND_NOTIFICATION(INVALID_COOKIE);
			return;
		}

		if (is_zero_cookie(md->hdr.isa_rcookie)) {
			/* initial message from initiator
			 * ??? what if this is a duplicate of another message?
			 */
			if (md->hdr.isa_flags & ISAKMP_FLAGS_v1_ENCRYPTION) {
				libreswan_log("initial phase 1 message is invalid:"
					      " its Encrypted Flag is on");
				SEND_NOTIFICATION(INVALID_FLAGS);
				return;
			}

			/* don't build a state until the message looks tasty */
			from_state = (md->hdr.isa_xchg == ISAKMP_XCHG_IDPROT ?
				      STATE_MAIN_R0 : STATE_AGGR_R0);
		} else {
			/* not an initial message */

			st = find_state_ikev1(md->hdr.isa_icookie,
					      md->hdr.isa_rcookie,
					      md->hdr.isa_msgid);

			if (st == NULL) {
				/* perhaps this is a first message from the responder
				 * and contains a responder cookie that we've not yet seen.
				 */
				st = find_state_ikev1(md->hdr.isa_icookie,
						      zero_cookie,
						      md->hdr.isa_msgid);

				if (st == NULL) {
					libreswan_log(
						"phase 1 message is part of an unknown exchange");
					/* XXX Could send notification back */
					return;
				}
			}
			set_cur_state(st);
			from_state = st->st_state;
		}
		break;

	case ISAKMP_XCHG_INFO:  /* an informational exchange */
		st = ikev1_find_info_state(md->hdr.isa_icookie, md->hdr.isa_rcookie,
				     &md->sender, v1_MAINMODE_MSGID);

		if (st == NULL) {
			/*
			 * might be an informational response to our first
			 * message, in which case, we don't know the rcookie yet.
			 */
			st = find_state_ikev1(md->hdr.isa_icookie, zero_cookie,
					      v1_MAINMODE_MSGID);
		}

		if (st != NULL)
			set_cur_state(st);

		if (md->hdr.isa_flags & ISAKMP_FLAGS_v1_ENCRYPTION) {
			bool quiet = (st == NULL ||
				     (st->st_connection->policy & POLICY_OPPORTUNISTIC));

			if (st == NULL) {
				DBG(DBG_CONTROL, DBG_log(
						"Informational Exchange is for an unknown (expired?) SA with MSGID:0x%08lx",
							(unsigned long)md->hdr.isa_msgid));

				/* Let's try to log some info about these to track them down */
				DBG(DBG_CONTROL, {
					    DBG_dump("- unknown SA's md->hdr.isa_icookie:",
						    md->hdr.isa_icookie,
						    COOKIE_SIZE);
					    DBG_dump("- unknown SA's md->hdr.isa_rcookie:",
						    md->hdr.isa_rcookie,
						    COOKIE_SIZE);
				    });

				/* XXX Could send notification back */
				return;
			}

			if (!IS_ISAKMP_ENCRYPTED(st->st_state)) {
				if (!quiet) {
					loglog(RC_LOG_SERIOUS, "encrypted Informational Exchange message is invalid because no key is known");
				}
				/* XXX Could send notification back */
				return;
			}

			if (md->hdr.isa_msgid == v1_MAINMODE_MSGID) {
				if (!quiet) {
					loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because it has a Message ID of 0");
				}
				/* XXX Could send notification back */
				return;
			}

			if (!unique_msgid(st, md->hdr.isa_msgid)) {
				if (!quiet) {
					loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because it has a previously used Message ID (0x%08lx)",
						(unsigned long)md->hdr.isa_msgid);
				}
				/* XXX Could send notification back */
				return;
			}
			st->st_msgid_reserved = FALSE;

			init_phase2_iv(st, &md->hdr.isa_msgid);
			new_iv_set = TRUE;

			from_state = STATE_INFO_PROTECTED;
		} else {
			if (st != NULL &&
			    IS_ISAKMP_AUTHENTICATED(st->st_state)) {
				if ((st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					loglog(RC_LOG_SERIOUS, "Informational Exchange message must be encrypted");
				}
				/* XXX Could send notification back */
				return;
			}
			from_state = STATE_INFO;
		}
		break;

	case ISAKMP_XCHG_QUICK: /* part of a Quick Mode exchange */

		if (is_zero_cookie(md->hdr.isa_icookie)) {
			DBG(DBG_CONTROL, DBG_log(
				"Quick Mode message is invalid because it has an Initiator Cookie of 0"));
			SEND_NOTIFICATION(INVALID_COOKIE);
			return;
		}

		if (is_zero_cookie(md->hdr.isa_rcookie)) {
			DBG(DBG_CONTROL, DBG_log(
				"Quick Mode message is invalid because it has a Responder Cookie of 0"));
			SEND_NOTIFICATION(INVALID_COOKIE);
			return;
		}

		if (md->hdr.isa_msgid == v1_MAINMODE_MSGID) {
			DBG(DBG_CONTROL, DBG_log(
				"Quick Mode message is invalid because it has a Message ID of 0"));
			SEND_NOTIFICATION(INVALID_MESSAGE_ID);
			return;
		}

		st = find_state_ikev1(md->hdr.isa_icookie, md->hdr.isa_rcookie,
				      md->hdr.isa_msgid);

		if (st == NULL) {
			/* No appropriate Quick Mode state.
			 * See if we have a Main Mode state.
			 * ??? what if this is a duplicate of another message?
			 */
			st = find_state_ikev1(md->hdr.isa_icookie,
					      md->hdr.isa_rcookie,
					      v1_MAINMODE_MSGID);

			if (st == NULL) {
				DBG(DBG_CONTROL, DBG_log(
					"Quick Mode message is for a non-existent (expired?) ISAKMP SA"));
				/* XXX Could send notification back */
				return;
			}

			if (st->st_oakley.doing_xauth) {
				DBG(DBG_CONTROL, DBG_log(
					"Cannot do Quick Mode until XAUTH done."));
				return;
			}

			/* Have we just given an IP address to peer? */
			if (st->st_state == STATE_MODE_CFG_R2) {
				/* ISAKMP is up... */
				change_state(st, STATE_MAIN_R3);
			}

#ifdef SOFTREMOTE_CLIENT_WORKAROUND
			/* See: http://popoludnica.pl/?id=10100110 */
			if (st->st_state == STATE_MODE_CFG_R1) {
				libreswan_log(
					"SoftRemote workaround: Cannot do Quick Mode until MODECFG done.");
				return;
			}
#endif

			set_cur_state(st);

			if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {
				if (DBGP(DBG_OPPO) || (st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because it is for an incomplete ISAKMP SA");
				}
				SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
				return;
			}

			if (!unique_msgid(st, md->hdr.isa_msgid)) {
				if (DBGP(DBG_OPPO) || (st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					loglog(RC_LOG_SERIOUS, "Quick Mode I1 message is unacceptable because it uses a previously used Message ID 0x%08lx (perhaps this is a duplicated packet)",
						(unsigned long) md->hdr.isa_msgid);
				}
				SEND_NOTIFICATION(INVALID_MESSAGE_ID);
				return;
			}
			st->st_msgid_reserved = FALSE;

			/* Quick Mode Initial IV */
			init_phase2_iv(st, &md->hdr.isa_msgid);
			new_iv_set = TRUE;

			from_state = STATE_QUICK_R0;
		} else {
			if (st->st_oakley.doing_xauth) {
				if (DBGP(DBG_OPPO) ||
				    (st->st_connection->policy & POLICY_OPPORTUNISTIC) == LEMPTY) {
					libreswan_log("Cannot do Quick Mode until XAUTH done.");
				}
				return;
			}
			set_cur_state(st);
			from_state = st->st_state;
		}

		break;

	case ISAKMP_XCHG_MODE_CFG:
		if (is_zero_cookie(md->hdr.isa_icookie)) {
			DBG(DBG_CONTROL, DBG_log("Mode Config message is invalid because it has an Initiator Cookie of 0"));
			/* XXX Could send notification back */
			return;
		}

		if (is_zero_cookie(md->hdr.isa_rcookie)) {
			DBG(DBG_CONTROL, DBG_log("Mode Config message is invalid because it has a Responder Cookie of 0"));
			/* XXX Could send notification back */
			return;
		}

		if (md->hdr.isa_msgid == 0) {
			DBG(DBG_CONTROL, DBG_log("Mode Config message is invalid because it has a Message ID of 0"));
			/* XXX Could send notification back */
			return;
		}

		st = ikev1_find_info_state(md->hdr.isa_icookie, md->hdr.isa_rcookie,
				     &md->sender, md->hdr.isa_msgid);

		if (st == NULL) {
			DBG(DBG_CONTROL, DBG_log(
				"No appropriate Mode Config state yet.See if we have a Main Mode state"));
			/* No appropriate Mode Config state.
			 * See if we have a Main Mode state.
			 * ??? what if this is a duplicate of another message?
			 */
			st = ikev1_find_info_state(md->hdr.isa_icookie,
					     md->hdr.isa_rcookie,
					     &md->sender, 0);

			if (st == NULL) {
				DBG(DBG_CONTROL, DBG_log(
					"Mode Config message is for a non-existent (expired?) ISAKMP SA"));
				/* XXX Could send notification back */
				return;
			}

			set_cur_state(st);

			DBG(DBG_CONTROLMORE, DBG_log(" processing received "
						     "isakmp_xchg_type %s.",
						     enum_show(&ikev1_exchange_names,
							       md->hdr.isa_xchg)));
			DBG(DBG_CONTROLMORE, DBG_log(" this is a%s%s%s%s",
						     st->st_connection->spd.
						     this.xauth_server ?
						     " xauthserver" : "",
						     st->st_connection->spd.
						     this.xauth_client ?
						     " xauthclient" : "",
						     st->st_connection->spd.
						     this.modecfg_server ?
						     " modecfgserver" : "",
						     st->st_connection->spd.
						     this.modecfg_client  ?
						     " modecfgclient" : ""
						     ));

			if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {
				DBG(DBG_CONTROLMORE, DBG_log(
					"Mode Config message is unacceptable because it is for an incomplete ISAKMP SA (state=%s)",
				       enum_name(&state_names, st->st_state)));
				/* XXX Could send notification back */
				return;
			}
			DBG(DBG_CONTROLMORE, DBG_log(" call  init_phase2_iv"));
			init_phase2_iv(st, &md->hdr.isa_msgid);
			new_iv_set = TRUE;

			/*
			 * okay, now we have to figure out if we are receiving a bogus
			 * new message in an oustanding XAUTH server conversation
			 * (i.e. a reply to our challenge)
			 * (this occurs with some broken other implementations).
			 *
			 * or if receiving for the first time, an XAUTH challenge.
			 *
			 * or if we are getting a MODECFG request.
			 *
			 * we distinguish these states because we cannot both be an
			 * XAUTH server and client, and our policy tells us which
			 * one we are.
			 *
			 * to complicate further, it is normal to start a new msgid
			 * when going from one state to another, or when restarting
			 * the challenge.
			 *
			 */

			if (st->st_connection->spd.this.xauth_server &&
			    st->st_state == STATE_XAUTH_R1 &&
			    st->quirks.xauth_ack_msgid) {
				from_state = STATE_XAUTH_R1;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s state is STATE_XAUTH_R1 and quirks.xauth_ack_msgid is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.xauth_client
				   &&
				   IS_PHASE1(st->st_state)) {
				from_state = STATE_XAUTH_I0;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is xauthclient and IS_PHASE1() is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.xauth_client
				   &&
				   st->st_state == STATE_XAUTH_I1) {
				/*
				 * in this case, we got a new MODECFG message after I0, maybe
				 * because it wants to start over again.
				 */
				from_state = STATE_XAUTH_I0;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is xauthclient and state == STATE_XAUTH_I1",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.modecfg_server
				   &&
				   IS_PHASE1(st->st_state)) {
				from_state = STATE_MODE_CFG_R0;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is modecfgserver and IS_PHASE1() is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else if (st->st_connection->spd.this.modecfg_client
				   &&
				   IS_PHASE1(st->st_state)) {
				from_state = STATE_MODE_CFG_R1;
				DBG(DBG_CONTROLMORE, DBG_log(
					" set from_state to %s this is modecfgclient and IS_PHASE1() is TRUE",
					    enum_name(&state_names,
						      st->st_state
						      )));
			} else {
				DBG(DBG_CONTROLMORE, DBG_log(
					"received isakmp_xchg_type %s",
					    enum_show(&ikev1_exchange_names,
						      md->hdr.isa_xchg)));
				DBG(DBG_CONTROLMORE, DBG_log(
					"this is a%s%s%s%s in state %s. Reply with UNSUPPORTED_EXCHANGE_TYPE",
					    st->st_connection
					    ->spd.this.xauth_server ?
					    " xauthserver" : "",
					    st->st_connection
					    ->spd.this.xauth_client ?
					    " xauthclient" : "",
					    st->st_connection
					    ->spd.this.modecfg_server ?
					    " modecfgserver" :
					    "",
					    st->st_connection
					    ->spd.this.modecfg_client  ?
					    " modecfgclient" :
					    "",
					    enum_name(&
						      state_names,
						      st->st_state)
					    ));
				return;
			}
		} else {
			if (st->st_connection->spd.this.xauth_server &&
			    IS_PHASE1(st->st_state)) {
				/* Switch from Phase1 to Mode Config */
				DBG(DBG_CONTROL, DBG_log(
					"We were in phase 1, with no state, so we went to XAUTH_R0"));
				change_state(st, STATE_XAUTH_R0);
			}

			/* otherweise, this is fine, we continue in the state we are in */
			set_cur_state(st);
			from_state = st->st_state;
		}

		break;

	case ISAKMP_XCHG_NGRP:
	default:
		DBG(DBG_CONTROL, DBG_log("unsupported exchange type %s in message",
			      enum_show(&ikev1_exchange_names, md->hdr.isa_xchg)));
		SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE);
		return;
	}

	/* We have found a from_state, and perhaps a state object.
	 * If we need to build a new state object,
	 * we wait until the packet has been sanity checked.
	 */

	/* We don't support the Commit Flag.  It is such a bad feature.
	 * It isn't protected -- neither encrypted nor authenticated.
	 * A man in the middle turns it on, leading to DoS.
	 * We just ignore it, with a warning.
	 */
	if (md->hdr.isa_flags & ISAKMP_FLAGS_v1_COMMIT)
		DBG(DBG_CONTROL, DBG_log(
			"IKE message has the Commit Flag set but Pluto doesn't implement this feature due to security concerns; ignoring flag"));


	/* Handle IKE fragmentation payloads */
	if (md->hdr.isa_np == ISAKMP_NEXT_IKE_FRAGMENTATION) {
		struct isakmp_ikefrag fraghdr;
		struct ike_frag *ike_frag, **i;
		int last_frag_index = 0;  /* index of the last fragment */
		pb_stream frag_pbs;

		if (st == NULL) {
			DBG(DBG_CONTROL, DBG_log(
				"received IKE fragment, but have no state. Ignoring packet."));
			return;
		}

		if ((st->st_connection->policy & POLICY_IKE_FRAG_ALLOW) == 0) {
			DBG(DBG_CONTROL, DBG_log(
			       "discarding IKE fragment packet - fragmentation not allowed by local policy (ike_frag=no)"));
			return;
		}

		if (!in_struct(&fraghdr, &isakmp_ikefrag_desc,
			       &md->message_pbs, &frag_pbs) ||
		    pbs_room(&frag_pbs) != fraghdr.isafrag_length ||
		    fraghdr.isafrag_np != 0 ||
		    fraghdr.isafrag_number == 0 || fraghdr.isafrag_number >
		    16) {
			SEND_NOTIFICATION(PAYLOAD_MALFORMED);
			return;
		}

		DBG(DBG_CONTROL,
		    DBG_log("received IKE fragment id '%d', number '%u'%s",
			    fraghdr.isafrag_id,
			    fraghdr.isafrag_number,
			    (fraghdr.isafrag_flags == 1) ? "(last)" : ""));

		ike_frag = alloc_thing(struct ike_frag, "ike_frag");
		ike_frag->md = md;
		ike_frag->index = fraghdr.isafrag_number;
		ike_frag->last = (fraghdr.isafrag_flags & 1);
		ike_frag->size = pbs_left(&frag_pbs);
		ike_frag->data = frag_pbs.cur;

#if 0
/* is this ever hit? It was wrongly checking one byte instead of 4 bytes of marker */
		/* Strip non-ESP marker from first fragment */
		if (md->iface->ike_float && ike_frag->index == 1 &&
		    (ike_frag->size >= NON_ESP_MARKER_SIZE &&
		     memeq(non_ESP_marker, ike_frag->data,
			    NON_ESP_MARKER_SIZE))) {
			ike_frag->data += NON_ESP_MARKER_SIZE;
			ike_frag->size -= NON_ESP_MARKER_SIZE;
		}
#endif

		/* Add the fragment to the state */
		i = &st->ike_frags;
		for (;;) {
			if (ike_frag != NULL) {
				/* Still looking for a place to insert ike_frag */
				if (*i == NULL ||
				    (*i)->index > ike_frag->index) {
					ike_frag->next = *i;
					*i = ike_frag;
					ike_frag = NULL;
				} else if ((*i)->index == ike_frag->index) {
					/* Replace fragment with same index */
					struct ike_frag *old = *i;

					ike_frag->next = old->next;
					*i = ike_frag;
					release_md(old->md);
					pfree(old);
					ike_frag = NULL;
				}
			}

			if (*i == NULL)
				break;

			if ((*i)->last)
				last_frag_index = (*i)->index;

			i = &(*i)->next;
		}

		/* We have the last fragment, reassemble if complete */
		if (last_frag_index != 0) {
			size_t size = 0;
			int prev_index = 0;
			struct ike_frag *frag;

			for (frag = st->ike_frags; frag; frag = frag->next) {
				size += frag->size;
				if (frag->index != ++prev_index) {
					break; /* fragment list incomplete */
				} else if (frag->index == last_frag_index) {
					struct msg_digest *whole_md = alloc_md();
					u_int8_t *buffer = alloc_bytes(size,
								       "IKE fragments buffer");
					size_t offset = 0;

					whole_md->iface = frag->md->iface;
					whole_md->sender = frag->md->sender;
					whole_md->sender_port =
						frag->md->sender_port;

					/* Reassemble fragments in buffer */
					frag = st->ike_frags;
					while (frag != NULL &&
					       frag->index <= last_frag_index)
					{
						passert(offset + frag->size <=
							size);
						memcpy(buffer + offset,
						       frag->data, frag->size);
						offset += frag->size;
						frag = frag->next;
					}

					init_pbs(&whole_md->packet_pbs, buffer, size,
						 "packet");

					process_packet(&whole_md);
					release_any_md(&whole_md);
					release_fragments(st);
					/* optimize: if receiving fragments, immediately respond with fragments too */
					st->st_seen_fragments = TRUE;
					DBG(DBG_CONTROL, DBG_log(
						" updated IKE fragment state to respond using fragments without waiting for re-transmits"));
					break;
				}
			}
		}

		/* Don't release the md, taken care of by the ike_frag code */
		/* ??? I'm not sure -- DHR */
		*mdp = NULL;
		return;
	}

	/* Set smc to describe this state's properties.
	 * Look up the appropriate microcode based on state and
	 * possibly Oakley Auth type.
	 */
	passert(STATE_IKE_FLOOR <= from_state && from_state <= STATE_IKE_ROOF);
	smc = ike_microcode_index[from_state - STATE_IKE_FLOOR];

	if (st != NULL) {
		oakley_auth_t baseauth =
			xauth_calcbaseauth(st->st_oakley.auth);

		while (!LHAS(smc->flags, baseauth)) {
			smc++;
			passert(smc->state == from_state);
		}
	}

	if (state_busy(st))
		return;

	/* Detect and handle duplicated packets.
	 * This won't work for the initial packet of an exchange
	 * because we won't have a state object to remember it.
	 * If we are in a non-receiving state (terminal), and the preceding
	 * state did transmit, then the duplicate may indicate that that
	 * transmission wasn't received -- retransmit it.
	 * Otherwise, just discard it.
	 * ??? Notification packets are like exchanges -- I hope that
	 * they are idempotent!
	 */
	if (st != NULL &&
	    st->st_rpacket.ptr != NULL &&
	    st->st_rpacket.len == pbs_room(&md->packet_pbs) &&
	    memeq(st->st_rpacket.ptr, md->packet_pbs.start,
		   st->st_rpacket.len)) {
		if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE) {
			if (st->st_retransmit < MAXIMUM_v1_ACCEPTED_DUPLICATES) {
				st->st_retransmit++;
				loglog(RC_RETRANSMISSION,
				       "retransmitting in response to duplicate packet; already %s",
				       enum_name(&state_names, st->st_state));
				resend_ike_v1_msg(st,
						  "retransmit in response to duplicate");
			} else {
				loglog(RC_LOG_SERIOUS,
				       "discarding duplicate packet -- exhausted retransmission; already %s",
				       enum_name(&state_names, st->st_state));
			}
		} else {
			loglog(RC_LOG_SERIOUS,
			       "discarding duplicate packet; already %s",
			       enum_name(&state_names, st->st_state));
		}
		return;
	}

	/* save values for use in resumption of processing below.
	 * (may be suspended due to crypto operation not yet complete)
	 */
	md->st = st;
	md->from_state = from_state;
	md->smc = smc;
	md->new_iv_set = new_iv_set;

	/*
	 * look for encrypt packets. We cannot handle them if we have not
	 * yet calculated the skeyids. We will just store the packet in
	 * the suspended state, since the calculation is likely underway.
	 *
	 * note that this differs from above, because skeyid is calculated
	 * in between states. (or will be, once DH is async)
	 *
	 */
	if ((md->hdr.isa_flags & ISAKMP_FLAGS_v1_ENCRYPTION) &&
	    st != NULL && !st->hidden_variables.st_skeyid_calculated ) {
		DBG(DBG_CRYPT | DBG_CONTROL, {
			ipstr_buf b;
			DBG_log("received encrypted packet from %s:%u but exponentiation still in progress",
				ipstr(&md->sender, &b),
				(unsigned)md->sender_port);
		});

		/* if there was a previous packet, let it go, and go with most
		 * recent one.
		 */
		if (st->st_suspended_md != NULL) {
			DBG(DBG_CONTROL,
			    DBG_log("releasing suspended operation before completion: %p",
				    st->st_suspended_md));
			release_any_md(&st->st_suspended_md);
		}

		set_suspended(st, md);
		*mdp = NULL;
		return;
	}

	process_packet_tail(mdp);
	/* our caller will release_any_md(mdp); */
}
