// 802.1x thingy
//
// what do we have to do:
//
// be able to send/receive EAPOL frames
// implement Supplicant state machine and sub-machine
// set wep keys when applicable
//
// 802.1x thingy
//
//
// our job:
//
// get access tocard interface
// read/write eapol frames
// be able to set wep keys
//
// supplicant state machine
// key receival state machine
// auth interaction
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <ip.h>
#include "dat.h"
#include "fns.h"
typedef enum PortControl {
Auto,
ForceUnauthorized,
ForceAuthorized,
} PortControl;
static char * sPortControl[] = {
"Auto",
"ForceUnauthorized",
"ForceAuthorized",
};
typedef enum AuthState {
Unauthorized,
Authorized,
} AuthState;
static char *sAuthState[] = {
"Unauthorized",
"Authorized",
};
// Supplicant PAE state machine (8.2.11) states
enum {
Logoff,
Disconnected,
Connecting,
Authenticating,
Held,
Authenticated,
Restart,
ForceAuth,
ForceUnauth,
};
static char *pnames[] = {
[Logoff] "Logoff",
[Disconnected] "Disconnected",
[Connecting] "Connecting",
[Authenticating] "Authenticating",
[Held] "Held",
[Authenticated] "Authenticated",
[Restart] "Restart",
[ForceAuth] "ForceAuth",
[ForceUnauth] "ForceUnauth",
};
// Supplicant Backend state machine (8.2.12) states
enum {
Request,
Response,
Success,
Fail,
Timeout,
Idle,
Initialize,
Receive,
};
static char *bnames[] = {
[Request] "Request",
[Response] "Response",
[Success] "Success",
[Fail] "Fail",
[Timeout] "Timeout",
[Idle] "Idle",
[Initialize] "Initialize",
[Receive] "Receive",
};
typedef struct backendstate {
// Supplicant Backend state machine constants (sect 8.2.12.1.2)
int authPeriod;
int bState; // Backend state
// Supplicant Backend state machine variables (sect 8.2.12.1.1)
int eapNoResp;
int eapReq;
int eapResp;
// Timers (sect 8.2.2.1)
Timer *authWhile;
} backendstate;
typedef struct PAEstate {
// Supplicant PAE state machine constants (sect 8.2.11.1.2)
int heldPeriod;
int startPeriod;
int maxStart;
// Supplicant PAE state machine variables (sect 8.2.11.1)
int eapRestart;
int logoffSent;
PortControl portMode; // sPortMode;
int startCount;
int userLogoff;
int pState; // PAE state
// Timers (sect 8.2.2.1)
Timer *heldWhile;
Timer *startWhen;
backendstate;
Etherstate *e;
Phasestate *p;
// Global variables (sect 8.2.2.2)
int eapolEap;
int initialize;
PortControl portControl;
int portEnabled;
AuthState portStatus;
int portValid; // needs work. happens if we cannot see the AP; ifstats shows ap = 4444444 or so
int suppAbort;
int suppFail;
AuthState suppPortStatus;
int suppSuccess;
int suppTimeout;
// other
int expectTtlsStart;
Packet *rxEtherEap;
Packet *txEtherEap;
char *prompt;
char *options;
Channel *tickchan;
Channel *portchan;
Channel *backstart;
Channel *backdone;
vlong paeTime;
vlong backTime;
vlong startTime;
vlong restartTime;
vlong eapidTime;
vlong noteTime;
} PAEstate;
// other
static char buf[2048];
// ========== Port timers 'state machine' (8.2.3)
// see timer.c
// ==========
static PAEstate theState;
// ========== receive eapol frames
// see ether.c:/^etherproc
// ========== Key receive 'state machine' (8.2.7)
// XXX do we do this in a separate thread/proc, or in the main one?
// see key.c:/^handleKey
// ========== Supplicant backend state machine
// clean up/initialize
static void
abortSupp(PAEstate *s)
{
s->e->eapSuccess = 0;
s->e->eapFail = 0;
s->eapNoResp = 0;
s->eapReq = 0;
s->eapResp = 0;
s->suppAbort = 0;
// abortTTLS();
}
static void
build_eap(Eap*t, int code, int id, int datalen)
{
t->code = code;
t->id = id;
hnputs(t->ln, EAPHDR + datalen);
}
static void
show_notification(PAEstate *s, uchar *m, int l)
{
// should do better: rfc3748 says:
// s contains UTF-8 encoded ISO 10646 [RFC2279].
s->noteTime = nsec();
memset(buf, 0, sizeof(m));
memcpy(buf, m, l);
logall("notification: %s", buf);
appendlog(getNotesbuf(), 0, "%s", buf);
}
static void
getSuppRsp(PAEstate *s)
{
// handle rxEtherEap
// build txEtherEap
Packet *rx, *tx;
uchar *p, *beyond;
char *ident, *prompt;
int len;
int tlssucces, tlsfailed;
loglog("getSuppRsp %p", s->rxEtherEap);
if (s->eapResp || s->eapNoResp)
logall("oops... getSuppRsp called while result previous of prev call pending");
rx = s->rxEtherEap;
tx = s->e->pktt;
s->txEtherEap = tx;
memset(s->txEtherEap->b, 0, Pktlen);
switch(rx->eap->code) {
case EapRequest:
if (debug) print("getSuppRsp EapRequest: %d \n", rx->eap->data[0]);
switch(rx->eap->data[0]) {
case EapTpIdentity:
// data format: [ prompt ] [ '\0' piggy-backed-options ]
// show prompt? extract options?
beyond = rx->eapol->data + nhgets(rx->eap->ln);
p = &rx->eap->data[1];
prompt = (char*)p;
for (; *p != '\0' && p+1 < beyond; p++)
;
memset(buf, 0, sizeof(buf));
if (*p == '\0' && p+1 < beyond) {
memcpy(buf, p+1, beyond - (p+1));
logall("received EAP Identity request, prompt=\"%s\" options=\"%s\"", prompt, buf);
free(s->prompt);
s->prompt = strdup(prompt);
free(s->options);
s->options = strdup(buf);
// while ((p = strchr(buf, ',')) != nil)
// *p = '\n';
} else {
memcpy(buf, &rx->eap->data[1], beyond - &rx->eap->data[1]);
logall("received EAP Identity request, data=\"%s\"", buf);
free(s->prompt);
s->prompt = strdup(buf);
free(s->options);
s->options = nil;
}
// the following is a HACK.
// but: SNT macosX notes only mention config of
// internal username and password (for TTLS-PAP),
// and allow leaving external identity blank.
// rfc3748 specifically says to _not_ include the
// username in the external identity
if ((ident = strchr(myId, '@')) == nil)
ident = "";
tx->eap->data[0] = EapTpIdentity;
memcpy(&tx->eap->data[1], ident, strlen(ident));
build_eap(tx->eap, EapResponse, rx->eap->id, 1+strlen(ident));
s->eapResp = 1;
s->expectTtlsStart = 1;
break;
case EapTpNotification:
tx->eap->data[0] = EapTpNotification;
build_eap(tx->eap, EapResponse, rx->eap->id, 1);
s->eapResp = 1;
show_notification(s, &rx->eap->data[1] , nhgets(rx->eap->ln)-EAPHDR+1);
break;
case EapTpTtls:
tlssucces = 0;
tlsfailed = 0;
rx->p = rx->eap->data;
rx->n = nhgets(rx->eap->ln)-EAPHDR;
tx->p = tx->eap->data;
tx->n = ETHERMAXTU-ETHERHDR-EAPOLHDR-EAPHDR;
len = processTTLS(rx, tx, s->expectTtlsStart, &tlssucces, &tlsfailed);
if (tlsfailed)
loglog("processTTLS failed");
s->expectTtlsStart = 0;
if (len > 0) {
build_eap(tx->eap, EapResponse, rx->eap->id, len);
s->eapResp = 1;
} else
s->eapNoResp = 1;
break;
case EapTpNak: // only allowed in responses
case EapTpExtp:
case EapTpExus:
default:
// tell we can't deal with this type; tell we can only do ttls
tx->eap->data[0] = EapTpNak;
tx->eap->data[1] = EapTpTtls;
build_eap(tx->eap, EapResponse, rx->eap->id, 1+1);
s->eapResp = 1;
break;
}
break;
default:
logall("getSuppRsp unexpected eap type %d", rx->eap->code);
break;
}
if (s->eapResp) {
memcpy(tx->ether->s, rx->ether->d, 6);
memcpy(tx->ether->d, rx->ether->s, 6);
memcpy(tx->ether->t, rx->ether->t, 2);
tx->eapol->ver = rx->eapol->ver;
tx->eapol->tp = rx->eapol->tp;
memcpy(tx->eapol->ln, tx->eap->ln, 2);
tx->e = tx->eapol->data + nhgets(tx->eap->ln);
}
if (!(s->eapResp || s->eapNoResp || s->e->eapSuccess || s->e->eapFail))
logall("internal error - no eap result set\n");
// prepare for reuse
memset(rx->b, 0, Pktlen);
rx->e = 0; // or rx->e = rx->b; ???
s->eapReq = 0;
}
// transmit EAP-Packet EAPOL frame to Authenticator
static void
txSuppRsp(PAEstate *s)
{
int n, l, len;
Packet *p;
p = s->txEtherEap;
len = p->e - p->b;
l = (len > ETHERMINTU) ? len : ETHERMINTU;
if (debug) print("txSuppRsp writing to ether l=%d L=%d\n", l, len);
if (p->eapol->tp == EapolTpEap &&
p->eap->code == EapResponse &&
p->eap->data[0] == EapTpIdentity) {
logall("sending eap external identity");
s->eapidTime = nsec();
}
n = write(s->e->fd, p->b, l);
if (n != l)
logall("txSuppRsp: written %d of %d: %r", n, l);
loglog("txSuppRsp: written %d", n);
}
static void
btrans(PAEstate *s, int new)
{
loglog("back trans: %s -> %s",bnames[s->bState], bnames[new]);
s->bState = new;
s->backTime = nsec();
}
static int
back(PAEstate *s)
{
Packet *rx;
int done;
Alt a[] = {
/* c v op */
{s->e->packetc, &rx, CHANRCV},
{s->tickchan, nil, CHANRCV},
{s->e->statusc, nil, CHANRCV},
{nil, nil, CHANEND},
};
if (s->bState != Initialize && (s->initialize || s->suppAbort))
btrans(s, Initialize);
switch(s->bState) {
case Initialize:
abortSupp(s);
s->suppAbort = 0;
if (!s->initialize && !s->suppAbort) {
} else
logall("back Initialize: should not happen");
btrans(s, Idle);
break;
case Idle:
send(s->backdone, nil);
recv(s->backstart, nil);
if (s->eapolEap)
btrans(s, Request);
else if(s->e->eapSuccess)
btrans(s, Success);
else if(s->e->eapFail)
btrans(s, Fail);
else if(s->suppAbort )
btrans(s, Initialize);
else
logfatal(0, "back Idle: should not happen");
break;
case Request:
s->eapReq = 1;
getSuppRsp(s);
if (s->eapResp)
btrans(s, Response);
else if (s->eapNoResp)
btrans(s, Receive);
else if (s->e->eapFail)
btrans(s, Fail);
else if (s->e->eapSuccess)
btrans(s, Success);
else if(s->suppAbort )
btrans(s, Initialize);
else
logfatal(0, "back Request: should not happen");
break;
case Response:
txSuppRsp(s);
s->eapResp = 0;
btrans(s, Receive);
break;
case Receive:
s->eapolEap = 0;
startTimer(s->authWhile, s->authPeriod);
done = 0;
while(!done)
switch(alt(a)) {
case 0: /* eap received */
loglog("back Receive eap received");
done = 1;
s->rxEtherEap = rx;
s->eapolEap = 1;
btrans(s, Request);
break;
case 1: /* timer tick */
// loglog("back Receive timer tick");
tickTimer(s->authWhile);
if (s->authWhile->counter == 0) {
logall("authWhile timer expired");
done = 1;
btrans(s, Timeout);
}
break;
case 2: /* eapSuccess or eapFail */
loglog("back Receive eapSuccess or eapFail");
done = 1;
if (s->e->eapFail)
btrans(s, Fail);
else if (s->e->eapSuccess)
btrans(s, Success);
else
logfatal(0, "back Receive 2: should not happen");
break;
default:
logfatal(0, "back Receive: can't happen");
}
resetTimer(s->authWhile);
s->eapNoResp = 0;
break;
case Success:
// try to avoid race: first set vars, then unset s->eapSuccess
s->suppSuccess = 1;
s->e->keyRun=1;
s->portValid = 1; // we should actually check this
s->e->eapSuccess = 0;
btrans(s, Idle);
break;
case Fail:
s->suppFail = 1;
s->e->eapFail = 0;
btrans(s, Idle);
break;
case Timeout:
s->suppTimeout = 1;
btrans(s, Idle);
break;
}
return s->bState;
}
void
backproc(void *arg)
{
PAEstate *s;
s = arg;
for(;;) {
back(s);
}
}
// ========== Supplicant PAE state machine
static void
waitUntilUserLoggedOn(PAEstate *s)
{
s->userLogoff = 0;
}
static void
waitUntilPortEnabled(PAEstate *s)
{
s->portEnabled = 1;
}
static void
acknowledgeStart(PAEstate *s)
{
loglog("------ restarting ------");
syslog(0, logname, "restarting");
s->restartTime = nsec();
}
// build EAPOL-Start frame and transmit to Authenticator
static void
txStart(PAEstate *s)
{
Packet *tx;
// get fresh ap mac - we may have roamed
if (apetheraddr(s->e->apmac, s->e->dir) < 0)
logfatal(0, "could not read access point ether address from %s", s->e->dir);
loglog("sending EAPOL Start frame to %E", s->e->apmac);
tx = s->e->pktt;
s->txEtherEap = tx;
memset(s->txEtherEap->b, 0, Pktlen);
tx->eapol->ver = EapolVersion;
tx->eapol->tp = EapolTpStart;
memset(tx->eapol->ln, 0, 2);
memcpy(tx->ether->s, s->e->ourmac, 6);
memcpy(tx->ether->d, s->e->apmac, 6);
hnputs(tx->ether->t, ETEAPOL);
tx->e = tx->eapol->data;
txSuppRsp(s);
}
// build EAPOL-Logoff frame and transmit to Authenticator
static void
txLogoff(PAEstate *s)
{
USED(s);
}
static void
ptrans(PAEstate *s, int new)
{
loglog("pae trans: %s -> %s", pnames[s->pState], pnames[new]);
s->pState = new;
s->paeTime = nsec();
}
static int
pae(PAEstate *s)
{
int val, res;
Packet *rx;
int done;
Alt a_c[] = {
/* c v op */
{s->e->packetc, &rx, CHANRCV},
{s->tickchan, nil, CHANRCV},
{s->e->statusc, nil, CHANRCV},
{nil, nil, CHANEND},
};
Alt a_h[] = {
/* c v op */
{s->e->packetc, &rx, CHANRCV},
{s->tickchan, nil, CHANRCV},
{nil, nil, CHANEND},
};
Alt a_a[] = {
/* c v op */
{s->e->packetc, &rx, CHANRCV},
{s->portchan, &val, CHANRCV},
{nil, nil, CHANEND},
};
if (s->pState != Logoff && s->portEnabled && !s->initialize &&
s->userLogoff && !s->logoffSent)
ptrans(s, Logoff);
else if (s->pState != Disconnected &&
(s->initialize || !s->portEnabled ||
(s->portControl == Auto && s->portMode != s->portControl)))
ptrans(s, Disconnected);
else if (s->pState != ForceAuth && s->portEnabled && !s->initialize &&
s->portControl == ForceAuthorized && s->portMode != s->portControl)
ptrans(s, ForceAuth);
else if (s->pState != ForceUnauth && s->portEnabled && !s->initialize &&
s->portControl == ForceUnauthorized && s->portMode != s->portControl)
ptrans(s, ForceUnauth);
switch(s->pState) {
case Logoff:
txLogoff(s);
s->logoffSent = 1;
s->suppPortStatus = Unauthorized;
waitUntilUserLoggedOn(s); // s->userLogoff = 0
ptrans(s, Disconnected);
break;
case Disconnected:
s->portMode = Auto;
s->startCount = 0;
s->logoffSent = 0;
s->suppPortStatus = Unauthorized;
s->suppAbort = 1;
send(s->backstart, nil);
recv(s->backdone, nil);
waitUntilPortEnabled(s); // s->portEnabled = 1
ptrans(s, Connecting);
break;
case Connecting:
s->startCount ++;
s->eapolEap = 0;
clearlog(getNotesbuf()); // when should we do this???
txStart(s);
startTimer(s->startWhen, s->startPeriod);
done = 0;
while(!done)
switch(res = alt(a_c)) {
case 0: /* eap received */
loglog("pae Connecting eap received");
done = 1;
s->rxEtherEap = rx;
s->eapolEap = 1;
ptrans(s, Restart);
break;
case 1: /* timer tick */
// loglog("pae Connecting startWhen timer tick");
tickTimer(s->startWhen);
if (s->startWhen->counter == 0) {
logall("startWhen timer expired");
done = 1;
if (s->startCount < s->maxStart)
ptrans(s, Connecting);
else if (s->startCount >= s->maxStart && s->portValid) {
logall("startCount >= maxStart (==%d), assume auth-ed", s->maxStart);
ptrans(s, Authenticated);
} else if (s->startCount >= s->maxStart) {
logall("startCount >= maxStart (==%d), but port not valid", s->maxStart);
ptrans(s, Held);
} else
logfatal(0, "pae Connecting 0: should not happen");
}
break;
case 2: /* eapSuccess or eapFail */
loglog("pae Connecting eapSuccess or eapFail");
done = 1;
if (s->e->eapSuccess || s->e->eapFail)
ptrans(s, Authenticating);
else
logfatal(0, "pae Connecting 3: should not happen");
break;
default:
logfatal(0, "pae Connecting can't happen:%d", res);
}
resetTimer(s->startWhen);
break;
case Authenticating:
s->startCount = 0;
s->suppSuccess = 0;
s->suppFail = 0;
s->suppTimeout = 0;
s->e->keyRun = 0;
s->e->keyDone = 0;
send(s->backstart, nil);
recv(s->backdone, nil);
if (s->suppSuccess && s->portValid)
ptrans(s, Authenticated);
else if(s->suppSuccess)
USED(s); // ???
else if (s->suppFail || (s->e->keyDone && !s->portValid))
ptrans(s, Held);
else if (s->suppTimeout)
ptrans(s, Connecting);
else
logfatal(0, "pae Authenticating: should not happen");
break;
case Held:
startTimer(s->heldWhile, s->heldPeriod);
s->suppPortStatus = Unauthorized;
done = 0;
while(!done)
switch(res = alt(a_h)) {
case 0: /* eap received */
loglog("pae Held eap received");
done = 1;
s->rxEtherEap = rx;
s->eapolEap = 1;
ptrans(s, Restart);
break;
case 1: /* timer tick */
// loglog("pae Held timer tick");
tickTimer(s->heldWhile);
if (s->heldWhile->counter == 0) {
logall("heldWhile timer expired");
done = 1;
ptrans(s, Connecting);
}
break;
default:
logfatal(0, "pae Held can't happen:%d", res);
}
resetTimer(s->heldWhile);
break;
case Authenticated:
s->suppPortStatus = Authorized;
switch(res = alt(a_a)) {
case 0: /* eap received */
loglog("pae Authenticated eap received");
if (s->portValid) {
s->rxEtherEap = rx;
s->eapolEap = 1;
ptrans(s, Restart);
}
break;
case 1: /* port validity changed */
loglog("pae Authenticated port validity changed");
s->portValid = val;
if (!s->portValid)
ptrans(s, Disconnected);
break;
default:
logfatal(0, "pae Authenticated can't happen:%d", res);
}
break;
case Restart:
acknowledgeStart(s);
ptrans(s, Authenticating);
break;
case ForceAuth:
s->suppPortStatus = Authorized;
s->portMode = ForceAuthorized;
break;
case ForceUnauth:
s->suppPortStatus = Unauthorized;
s->portMode = ForceUnauthorized;
// no check??
txLogoff(s);
s->logoffSent = 1;
break;
}
//print("pae return: %s\n", pnames[s->pState]);
return s->pState;
}
// ========== run state machine
void
paeproc(void *arg)
{
PAEstate *s;
s = arg;
for(;;) {
pae(s);
}
}
// ========== fs support
typedef struct timeInfo {
int id;
vlong time;
} timeInfo;
static int
cmptimenfo(void*a, void*b)
{
timeInfo *ta, *tb;
vlong td;
ta = a ;
tb = b;
if (ta->time == 0 && tb->time > 0)
return 1;
if (ta->time > 0 && tb->time == 0)
return -1;
td = ta->time - tb->time;
if (td > 0)
return 1;
if (td < 0)
return -1;
return ta->id - tb->id;
}
enum {
InitTime = 0,
StartTime,
PaeTime,
BackTime,
eapidTime,
verdictTime,
ph1startTime,
ph1doneTime,
ph2startTime,
ph2doneTime,
KeyTime,
NoteTime,
NTime,
};
static char *timeNames[] = {
[InitTime] "Init",
[StartTime] "Start",
[PaeTime] "Pae",
[BackTime] "Back",
[eapidTime] "Eapid",
[verdictTime] "Verdict",
[ph1startTime] "Ph1start",
[ph1doneTime] "Ph1done",
[ph2startTime] "Ph2start",
[ph2doneTime] "Ph2done",
[KeyTime] "Key",
[NoteTime] "Note",
[NTime] "",
};
static timeInfo t[NTime];
static timeInfo*
getPAETimes(PAEstate *s)
{
t[InitTime].time = s->startTime;
t[InitTime].id = InitTime;
t[StartTime].time = s->restartTime;
t[StartTime].id = StartTime;
t[PaeTime].time = s->paeTime;
t[PaeTime].id = PaeTime;
t[BackTime].time = s->backTime;
t[BackTime].id = BackTime;
t[eapidTime].time = s->eapidTime;
t[eapidTime].id = eapidTime;
t[verdictTime].time = s->e->verdictTime;
t[verdictTime].id = verdictTime;
t[ph1startTime].time = s->p[0].startTime;
t[ph1startTime].id = ph1startTime;
t[ph1doneTime].time = s->p[0].doneTime;
t[ph1doneTime].id = ph1doneTime;
t[ph2startTime].time = s->p[1].startTime;
t[ph2startTime].id = ph2startTime;
t[ph2doneTime].time = s->p[1].doneTime;
t[ph2doneTime].id = ph2doneTime;
t[KeyTime].time = s->e->keyTime;
t[KeyTime].id = KeyTime;
t[NoteTime].time = s->noteTime;
t[NoteTime].id = NoteTime;
t[NTime].time = 0;
t[NTime].id = NTime;
qsort(t, NTime, sizeof(timeInfo), cmptimenfo);
return t;
}
void
getPAEStatus(char *b, int n)
{
PAEstate *s;
timeInfo *t;
int i;
s = &theState;
*b = '\0';
seprint(b+strlen(b), b+n, "Verdict:\t%s\n",
((s->e->eapSuccess || s->suppSuccess) ? "success" :
((s->e->eapFail || s->suppFail) ? "fail" : "")));
seprint(b+strlen(b), b+n, "AccessPoint: %E\n", s->e->apmac);
seprint(b+strlen(b), b+n, "EapId Prompt: %s\n", getstring(s->prompt));
seprint(b+strlen(b), b+n, "EapId Options: %s\n", getstring(s->options));
seprint(b+strlen(b), b+n, "Ph1type: %s\n", getstring(s->p[0].type));
seprint(b+strlen(b), b+n, "Ph2type: %s\n", getstring(s->p[1].type));
seprint(b+strlen(b), b+n, "PaeState: %s\n", pnames[s->pState]);
seprint(b+strlen(b), b+n, "EapRestart: %d\n", s->eapRestart);
seprint(b+strlen(b), b+n, "LogoffSent: %d\n", s->logoffSent);
seprint(b+strlen(b), b+n, "UserLogoff: %d\n", s->userLogoff);
seprint(b+strlen(b), b+n, "SPortMode: %s\n", sPortControl[s->portMode]);
seprint(b+strlen(b), b+n, "BackState: %s\n", bnames[s->bState]);
seprint(b+strlen(b), b+n, "EapNoResp: %d\n", s->eapNoResp);
seprint(b+strlen(b), b+n, "EapReq: %d\n", s->eapReq);
seprint(b+strlen(b), b+n, "EapResp: %d\n", s->eapResp);
seprint(b+strlen(b), b+n, "EapNoResp: %d\n", s->eapNoResp);
seprint(b+strlen(b), b+n, "EapFail: %d\n", s->e->eapFail);
seprint(b+strlen(b), b+n, "EapSuccess: %d\n", s->e->eapSuccess);
seprint(b+strlen(b), b+n, "Initialize: %d\n", s->initialize);
seprint(b+strlen(b), b+n, "PortControl: %s\n", sPortControl[s->portControl]);
seprint(b+strlen(b), b+n, "PortEnabled: %d\n", s->portEnabled);
seprint(b+strlen(b), b+n, "PortStatus: %s\n", sAuthState[s->portStatus]);
seprint(b+strlen(b), b+n, "SuppPortStatus: %s\n", sAuthState[s->suppPortStatus]);
seprint(b+strlen(b), b+n, "PortValid: %d\n", s->portValid);
seprint(b+strlen(b), b+n, "SuppSuccess: %d\n", s->suppSuccess);
seprint(b+strlen(b), b+n, "SuppFail: %d\n", s->suppFail);
seprint(b+strlen(b), b+n, "SuppTimeout: %d\n", s->suppTimeout);
seprint(b+strlen(b), b+n, "KeyRun: %d\n", s->e->keyRun);
seprint(b+strlen(b), b+n, "KeyDone: %d\n", s->e->keyDone);
t = getPAETimes(s);
for (i=0; i < NTime; i++)
seprint(b+strlen(b), b+n, "%s:\t%s\n", timeNames[t[i].id], nsctime(t[i].time));
seprint(b+strlen(b), b+n, "StartCount:\t%d\n", s->startCount);
seprint(b+strlen(b), b+n, "MaxStart:\t%d\n", s->maxStart);
seprint(b+strlen(b), b+n, "HeldWhile:\t%d\n", timerVal(s->heldWhile));
seprint(b+strlen(b), b+n, "HeldPeriod:\t%d\n", s->heldPeriod);
seprint(b+strlen(b), b+n, "StartWhen:\t%d\n", timerVal(s->startWhen));
seprint(b+strlen(b), b+n, "StartPeriod:\t%d\n", s->startPeriod);
seprint(b+strlen(b), b+n, "AuthWhile:\t%d\n", timerVal(s->authWhile));
seprint(b+strlen(b), b+n, "AuthPeriod:\t%d\n", s->authPeriod);
}
long
getChangetime(int qid)
{
PAEstate *s;
s = &theState;
switch(qid){
case Qstatus:
if (s->paeTime > s->backTime)
return nsec2sec(s->paeTime);
else
return nsec2sec(s->backTime);
case Qkeys:
return nsec2sec(s->e->keyTime);
case Qnote:
return nsec2sec(s->noteTime);
default:
return 0;
}
}
// ========== main thing
PAEstate*
init8021x(Etherstate *e, Timers *t, Phasestate *p)
{
PAEstate *s;
s = &theState;
memset(s, 0, sizeof(PAEstate));
s->e = e;
s->p = p;
s->heldPeriod = 60; //seconds
s->startPeriod = 30; //seconds
s->authPeriod = 30; //seconds
s->maxStart = 3;
s->heldWhile = addTimer(t, "heldWhile");
s->startWhen = addTimer(t, "startWhen");
s->authWhile = addTimer(t, "authWhile");
s->pState = Disconnected;
s->bState = Initialize;
s->startTime = nsec();
s->paeTime = s->startTime;
s->backTime = s->startTime;
// s->noteTime = s->startTime;
// s->restartTime = nsec();
s->portchan = chancreate(sizeof(int), 0);
s->backstart = chancreate(sizeof(int), 0);
s->backdone = chancreate(sizeof(int), 0);
s->tickchan = t->chan;
return s;
}
void
start8021xprocs(PAEstate *s)
{
procrfork(backproc, s, STACK, RFNAMEG|RFNOTEG);
recv(s->backdone, nil);
s->portEnabled = 1;
procrfork(paeproc, s, STACK, RFNAMEG|RFNOTEG);
}
|