eap_send_request(esp)
eap_state *esp;
{
	u_char *outp;
	u_char *lenloc;
	u_char *ptr;
	int outlen;
	int challen;
	char *str;
#ifdef USE_SRP
	struct t_server *ts;
	u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp;
	int i, j;
	struct b64state b64;
	SHA1_CTX ctxt;
#endif /* USE_SRP */

	/* Handle both initial auth and restart */
	if (esp->es_server.ea_state < eapIdentify &&
	    esp->es_server.ea_state != eapInitial) {
		esp->es_server.ea_state = eapIdentify;
		if (explicit_remote) {
			/*
			 * If we already know the peer's
			 * unauthenticated name, then there's no
			 * reason to ask.  Go to next state instead.
			 */
			esp->es_server.ea_peer = remote_name;
			esp->es_server.ea_peerlen = strlen(remote_name);
			eap_figure_next_state(esp, 0);
		}
	}

	if (esp->es_server.ea_maxrequests > 0 &&
	    esp->es_server.ea_requests >= esp->es_server.ea_maxrequests) {
		if (esp->es_server.ea_responses > 0)
			error("EAP: too many Requests sent");
		else
			error("EAP: no response to Requests");
		eap_send_failure(esp);
		return;
	}

	outp = outpacket_buf;
    
	MAKEHEADER(outp, PPP_EAP);

	PUTCHAR(EAP_REQUEST, outp);
	PUTCHAR(esp->es_server.ea_id, outp);
	lenloc = outp;
	INCPTR(2, outp);

	switch (esp->es_server.ea_state) {
	case eapIdentify:
		PUTCHAR(EAPT_IDENTITY, outp);
		str = "Name";
		challen = strlen(str);
		BCOPY(str, outp, challen);
		INCPTR(challen, outp);
		break;

	case eapMD5Chall:
		PUTCHAR(EAPT_MD5CHAP, outp);
		/*
		 * pick a random challenge length between
		 * MIN_CHALLENGE_LENGTH and MAX_CHALLENGE_LENGTH
		 */
		challen = (drand48() *
		    (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
			    MIN_CHALLENGE_LENGTH;
		PUTCHAR(challen, outp);
		esp->es_challen = challen;
		ptr = esp->es_challenge;
		while (--challen >= 0)
			*ptr++ = (u_char) (drand48() * 0x100);
		BCOPY(esp->es_challenge, outp, esp->es_challen);
		INCPTR(esp->es_challen, outp);
		BCOPY(esp->es_server.ea_name, outp, esp->es_server.ea_namelen);
		INCPTR(esp->es_server.ea_namelen, outp);
		break;

#ifdef USE_SRP
	case eapSRP1:
		PUTCHAR(EAPT_SRP, outp);
		PUTCHAR(EAPSRP_CHALLENGE, outp);

		PUTCHAR(esp->es_server.ea_namelen, outp);
		BCOPY(esp->es_server.ea_name, outp, esp->es_server.ea_namelen);
		INCPTR(esp->es_server.ea_namelen, outp);

		ts = (struct t_server *)esp->es_server.ea_session;
		assert(ts != NULL);
		PUTCHAR(ts->s.len, outp);
		BCOPY(ts->s.data, outp, ts->s.len);
		INCPTR(ts->s.len, outp);

		if (ts->g.len == 1 && ts->g.data[0] == 2) {
			PUTCHAR(0, outp);
		} else {
			PUTCHAR(ts->g.len, outp);
			BCOPY(ts->g.data, outp, ts->g.len);
			INCPTR(ts->g.len, outp);
		}

		if (ts->n.len != sizeof (wkmodulus) ||
		    BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) {
			BCOPY(ts->n.data, outp, ts->n.len);
			INCPTR(ts->n.len, outp);
		}
		break;

	case eapSRP2:
		PUTCHAR(EAPT_SRP, outp);
		PUTCHAR(EAPSRP_SKEY, outp);

		ts = (struct t_server *)esp->es_server.ea_session;
		assert(ts != NULL);
		BCOPY(ts->B.data, outp, ts->B.len);
		INCPTR(ts->B.len, outp);
		break;

	case eapSRP3:
		PUTCHAR(EAPT_SRP, outp);
		PUTCHAR(EAPSRP_SVALIDATOR, outp);
		PUTLONG(SRPVAL_EBIT, outp);
		ts = (struct t_server *)esp->es_server.ea_session;
		assert(ts != NULL);
		BCOPY(t_serverresponse(ts), outp, SHA_DIGESTSIZE);
		INCPTR(SHA_DIGESTSIZE, outp);

		if (pncrypt_setkey(0)) {
			/* Generate pseudonym */
			optr = outp;
			cp = (unsigned char *)esp->es_server.ea_peer;
			if ((j = i = esp->es_server.ea_peerlen) > 7)
				j = 7;
			clear[0] = i;
			BCOPY(cp, clear + 1, j);
			i -= j;
			cp += j;
			if (!DesEncrypt(clear, cipher)) {
				dbglog("no DES here; not generating pseudonym");
				break;
			}
			BZERO(&b64, sizeof (b64));
			outp++;		/* space for pseudonym length */
			outp += b64enc(&b64, cipher, 8, outp);
			while (i >= 8) {
				(void) DesEncrypt(cp, cipher);
				outp += b64enc(&b64, cipher, 8, outp);
				cp += 8;
				i -= 8;
			}
			if (i > 0) {
				BCOPY(cp, clear, i);
				cp += i;
				while (i < 8) {
					*cp++ = drand48() * 0x100;
					i++;
				}
				(void) DesEncrypt(clear, cipher);
				outp += b64enc(&b64, cipher, 8, outp);
			}
			outp += b64flush(&b64, outp);

			/* Set length and pad out to next 20 octet boundary */
			i = outp - optr - 1;
			*optr = i;
			i %= SHA_DIGESTSIZE;
			if (i != 0) {
				while (i < SHA_DIGESTSIZE) {
					*outp++ = drand48() * 0x100;
					i++;
				}
			}

			/* Obscure the pseudonym with SHA1 hash */
			SHA1Init(&ctxt);
			SHA1Update(&ctxt, &esp->es_server.ea_id, 1);
			SHA1Update(&ctxt, esp->es_server.ea_skey,
			    SESSION_KEY_LEN);
			SHA1Update(&ctxt, esp->es_server.ea_peer,
			    esp->es_server.ea_peerlen);
			while (optr < outp) {
				SHA1Final(dig, &ctxt);
				cp = dig;
				while (cp < dig + SHA_DIGESTSIZE)
					*optr++ ^= *cp++;
				SHA1Init(&ctxt);
				SHA1Update(&ctxt, &esp->es_server.ea_id, 1);
				SHA1Update(&ctxt, esp->es_server.ea_skey,
				    SESSION_KEY_LEN);
				SHA1Update(&ctxt, optr - SHA_DIGESTSIZE,
				    SHA_DIGESTSIZE);
			}
		}
		break;

	case eapSRP4:
		PUTCHAR(EAPT_SRP, outp);
		PUTCHAR(EAPSRP_LWRECHALLENGE, outp);
		challen = MIN_CHALLENGE_LENGTH +
		    ((MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH) * drand48());
		esp->es_challen = challen;
		ptr = esp->es_challenge;
		while (--challen >= 0)
			*ptr++ = drand48() * 0x100;
		BCOPY(esp->es_challenge, outp, esp->es_challen);
		INCPTR(esp->es_challen, outp);
		break;
#endif /* USE_SRP */

	default:
		return;
	}

	outlen = (outp - outpacket_buf) - PPP_HDRLEN;
	PUTSHORT(outlen, lenloc);

	output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN);

	esp->es_server.ea_requests++;

	if (esp->es_server.ea_timeout > 0)
		TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout);
}