From 5fe022b3c50305980b4a2f7d377798d733f360bd Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 4 Apr 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-04-04 --- bitsy/etherwavelan.c | 11 +- pc/etherga620.c | 7 +- pc/etherwavelan.c | 5 +- pc/mouse.c | 16 +++ pc/vganvidia.c | 248 +++++++++++++++++++++++++++++++++++ port/devtls.c | 300 +++++++++++++++++++++++++++++++++---------- 6 files changed, 515 insertions(+), 72 deletions(-) create mode 100644 pc/vganvidia.c diff --git a/bitsy/etherwavelan.c b/bitsy/etherwavelan.c index 07cc1ad6bebaf85477a4c939d2fee956821698e9..d5f618c30ae7afd34b307fe680ae65a3fd2e89f1 100644 --- a/bitsy/etherwavelan.c +++ b/bitsy/etherwavelan.c @@ -115,6 +115,7 @@ enum WTyp_Keys = 0xfcb0, WTyp_TxKey = 0xfcb1, WTyp_CurName = 0xfd41, + WTyp_BaseID = 0xfd42, // ID of the currently connected-to base station WTyp_CurTxRate = 0xfd44, // Current TX rate WTyp_HasCrypt = 0xfd4f, }; @@ -940,8 +941,16 @@ ifstat(Ether* ether, void* a, long n, ulong offset) PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom)); if(i == 3) PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName)); - else + else { + Wltv ltv; PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName)); + ltv.type = WTyp_BaseID; + ltv.len = 4; + if (w_inltv(ctlr, <v)) + print("#l%d: unable to read base station mac addr\n", ether->ctlrno); + l += snprint(p+l, READSTR-l, "Base station: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", + ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]); + } PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName)); PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName)); if (ltv_ins(ctlr, WTyp_HasCrypt) == 0) diff --git a/pc/etherga620.c b/pc/etherga620.c index d62a749ca11401d4e30d85a3c2d3398a0238494b..8e6db83cb5a9ff4540b05cd0d5d3c3f05776a7f9 100644 --- a/pc/etherga620.c +++ b/pc/etherga620.c @@ -228,7 +228,7 @@ enum { /* Host/NIC Interface ring sizes */ }; enum { - NrsrHI = 256, /* (WAS 128) Fill-level of Rsr (m.b. < Nrsr) */ + NrsrHI = 128, /* Fill-level of Rsr (m.b. < Nrsr) */ NrsrLO = 64, /* Level at which to top-up ring */ NrjrHI = 0, /* Fill-level of Rjr (m.b. < Nrjr) */ NrjrLO = 0, /* Level at which to top-up ring */ @@ -665,11 +665,11 @@ ga620init(Ether* edev) * These defaults are based on the tuning hints in the Alteon * Host/NIC Software Interface Definition and example software. */ - csr32w(ctlr, Rct, 1000); /* was 100 */ + csr32w(ctlr, Rct, 100); csr32w(ctlr, Sct, 0); csr32w(ctlr, St, 100000); csr32w(ctlr, SmcBD, Nsr/4); - csr32w(ctlr, RmcBD, 100); /* was 6 */ + csr32w(ctlr, RmcBD, 6); /* * Enable DMA Assist Logic. @@ -993,7 +993,6 @@ ga620pnp(Ether* edev) edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; edev->mbps = 1000; - edev->oq = qopen(512*1024, 1, 0, 0); /* * Check if the adapter's station address is to be overridden. diff --git a/pc/etherwavelan.c b/pc/etherwavelan.c index a1fa597ee82aa98e87986a672aef818452a0653f..1bf40286860a1eaaeb9947593760b3830a22117d 100644 --- a/pc/etherwavelan.c +++ b/pc/etherwavelan.c @@ -115,6 +115,7 @@ enum WTyp_Keys = 0xfcb0, WTyp_TxKey = 0xfcb1, WTyp_CurName = 0xfd41, + WTyp_BaseID = 0xfd42, // ID of the currently connected-to base station WTyp_CurTxRate = 0xfd44, // Current TX rate WTyp_HasCrypt = 0xfd4f, }; @@ -940,8 +941,10 @@ ifstat(Ether* ether, void* a, long n, ulong offset) PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom)); if(i == 3) PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName)); - else + else { PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName)); +// PRINTSTAT("Base station: %s\n", ltv_inname(ctlr, WTyp_BaseID)); + } PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName)); PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName)); if (ltv_ins(ctlr, WTyp_HasCrypt) == 0) diff --git a/pc/mouse.c b/pc/mouse.c index 522756fc2c95e865de94533ba3658151a8e77e8a..256b42a9a640dbefb33af2802515638294c2ce05 100644 --- a/pc/mouse.c +++ b/pc/mouse.c @@ -69,6 +69,12 @@ serialmouse(int port, char *type, int setspeed) * Also on laptops with AccuPoint AND external mouse, the * controller may deliver 3 or 4 bytes according to the type * of the external mouse; code must adapt. + * + * On the NEC Versa series (and perhaps others?) we seem to + * lose a byte from the packet every once in a while, which + * means we lose where we are in the instruction stream. + * To resynchronize, if we get a byte more than two seconds + * after the previous byte, we assume it's the first in a packet. */ static void ps2mouseputc(int c, int shift) @@ -76,8 +82,18 @@ ps2mouseputc(int c, int shift) static short msg[4]; static int nb; static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 }; + static ulong lasttick; + ulong m; int buttons, dx, dy; + /* + * Resynchronize in stream with timing; see comment above. + */ + m = MACHP(0)->ticks; + if(TK2SEC(m - lasttick) > 2) + nb = 0; + lasttick = m; + /* * check byte 0 for consistency */ diff --git a/pc/vganvidia.c b/pc/vganvidia.c new file mode 100644 index 0000000000000000000000000000000000000000..43e69accad4b8d8f4e06a9a4b9f04402124eb345 --- /dev/null +++ b/pc/vganvidia.c @@ -0,0 +1,248 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define Image IMAGE +#include +#include +#include +#include "screen.h" + +enum { + Pramin = 0x00710000, + Pramdac = 0x00680000 +}; + +enum { + hwCurPos = Pramdac + 0x0300, + hwCurImage = Pramin + (0x00010000 - 0x0800), +}; + +static ushort nvidiadid[] = { + 0x0020, /* Riva TNT */ + 0x0028, /* Riva TNT2 */ + 0x0029, /* Riva TNT2 (Ultra)*/ + 0x002C, /* Riva TNT2 (Vanta) */ + 0x002D, /* Riva TNT2 M64 */ + 0x00A0, /* Riva TNT2 (Integrated) */ + 0x0100, /* GeForce 256 */ + 0x0101, /* GeForce DDR */ + 0x0103, /* Quadro */ + 0x0110, /* GeForce2 MX */ + 0x0111, /* GeForce2 MX DDR */ + 0x0112, /* GeForce 2 Go */ + 0x0113, /* Quadro 2 MXR */ + 0x0150, /* GeForce2 GTS */ + 0x0151, /* GeForce2 GTS (rev 1) */ + 0x0152, /* GeForce2 Ultra */ + 0x0153, /* Quadro 2 Pro */ + 0, +}; + +static Pcidev* +nvidiapci(void) +{ + Pcidev *p; + ushort *did; + + if((p = pcimatch(nil, 0x10DE, 0)) == nil) + return nil; + for(did = nvidiadid; *did; did++){ + if(*did == p->did) + return p; + } + + return nil; +} + + +static ulong +nvidialinear(VGAscr* scr, int* size, int* align) +{ + Pcidev *p; + int oapsize, wasupamem; + ulong aperture, oaperture; + + oaperture = scr->aperture; + oapsize = scr->apsize; + wasupamem = scr->isupamem; + + aperture = 0; + if(p = nvidiapci()){ + aperture = p->mem[1].bar & ~0x0F; + *size = p->mem[1].size; + } + + if(wasupamem) { + if(oaperture == aperture) + return oaperture; + upafree(oaperture, oapsize); + } + scr->isupamem = 0; + + aperture = upamalloc(aperture, *size, *align); + if(aperture == 0){ + if(wasupamem && upamalloc(oaperture, oapsize, 0)){ + aperture = oaperture; + scr->isupamem = 1; + } + else + scr->isupamem = 0; + } + else + scr->isupamem = 1; + + return aperture; +} + +static void +nvidiaenable(VGAscr* scr) +{ + Pcidev *p; + Physseg seg; + ulong aperture; + int align, size; + + /* + * Only once, can't be disabled for now. + * scr->io holds the physical address of + * the MMIO registers. + */ + if(scr->io) + return; + p = nvidiapci(); + if(p == nil) + return; + + scr->io = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0); + if (scr->io == 0) + return; + + memset(&seg, 0, sizeof(seg)); + seg.attr = SG_PHYSICAL; + seg.name = smalloc(NAMELEN); + snprint(seg.name, NAMELEN, "nvidiammio"); + seg.pa = scr->io; + seg.size = p->mem[0].size; + addphysseg(&seg); + + size = p->mem[1].size; + align = 0; + aperture = nvidialinear(scr, &size, &align); + if(aperture) { + scr->aperture = aperture; + scr->apsize = size; + memset(&seg, 0, sizeof(seg)); + seg.attr = SG_PHYSICAL; + seg.name = smalloc(NAMELEN); + snprint(seg.name, NAMELEN, "nvidiascreen"); + seg.pa = aperture; + seg.size = size; + addphysseg(&seg); + } +} + +static void +nvidiacurdisable(VGAscr* scr) +{ + if(scr->io == 0) + return; + + vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01); +} + +static void +nvidiacurload(VGAscr* scr, Cursor* curs) +{ + ulong* p; + int i,j; + ushort c,s; + ulong tmp; + + if(scr->io == 0) + return; + + vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01); + + p = KADDR(scr->io + hwCurImage); + + for (i=0; i<16; i++) { + c = (curs->clr[2 * i] << 8) | curs->clr[2 * i+1]; + s = (curs->set[2 * i] << 8) | curs->set[2 * i+1]; + tmp = 0; + for (j=0; j<16; j++) { + if(s&0x8000) + tmp |= 0x80000000; + else if(c&0x8000) + tmp |= 0xFFFF0000; + if (j&0x1) { + *p++ = tmp; + tmp = 0; + } else { + tmp>>=16; + } + c<<=1; + s<<=1; + } + for (j=0; j<8; j++) + *p++ = 0; + } + for (i=0; i<256; i++) + *p++ = 0; + + scr->offset = curs->offset; + vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01); + + return; +} + +static int +nvidiacurmove(VGAscr* scr, Point p) +{ + ulong* cursorpos; + + if(scr->io == 0) + return 1; + + cursorpos = KADDR(scr->io + hwCurPos); + *cursorpos = ((p.y+scr->offset.y)<<16)|((p.x+scr->offset.x) & 0xFFFF); + + return 0; +} + +static void +nvidiacurenable(VGAscr* scr) +{ + nvidiaenable(scr); + if(scr->io == 0) + return; + + vgaxo(Crtx, 0x1F, 0x57); + + nvidiacurload(scr, &arrow); + nvidiacurmove(scr, ZP); + + vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01); +} + +VGAdev vganvidiadev = { + "nvidia", + + nvidiaenable, + nil, + nil, + nvidialinear, +}; + +VGAcur vganvidiacur = { + "nvidiahwgc", + + nvidiacurenable, + nvidiacurdisable, + nvidiacurload, + nvidiacurmove, +}; diff --git a/port/devtls.c b/port/devtls.c index 4145c501f4f71fbf9ec5223a586283cf5133594b..a1ed1fce2501fa82d0a75dfbdd4ac26d06256386 100644 --- a/port/devtls.c +++ b/port/devtls.c @@ -115,6 +115,67 @@ struct TlsRec int perm; }; +typedef struct TlsErrs TlsErrs; +struct TlsErrs{ + int err; + int sslerr; + int tlserr; + int fatal; + char *msg; +}; + +static TlsErrs tlserrs[] = { + {ECloseNotify, ECloseNotify, ECloseNotify, + 0, "remote close"}, + {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, + 1, "unexpected message"}, + {EBadRecordMac, EBadRecordMac, EBadRecordMac, + 1, "bad record MAC"}, + {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, + 1, "decryption failed"}, + {ERecordOverflow, EIllegalParameter, ERecordOverflow, + 1, "record too long"}, + {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, + 1, "decompression failed"}, + {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, + 1, "could not negotiate acceptable security paramters"}, + {ENoCertificate, ENoCertificate, ECertificateUnknown, + 1, "no appropriate certificate available"}, + {EBadCertificate, EBadCertificate, EBadCertificate, + 1, "corrupted or invalid certificate"}, + {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, + 1, "unsupported certificate type"}, + {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, + 1, "revoked certificate"}, + {ECertificateExpired, ECertificateExpired, ECertificateExpired, + 1, "expired certificate"}, + {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, + 1, "unacceptable certificate"}, + {EIllegalParameter, EIllegalParameter, EIllegalParameter, + 1, "illegal parameter"}, + {EUnknownCa, EHandshakeFailure, EUnknownCa, + 1, "unknown certificate authority"}, + {EAccessDenied, EHandshakeFailure, EAccessDenied, + 1, "access denied"}, + {EDecodeError, EIllegalParameter, EDecodeError, + 1, "error decoding message"}, + {EDecryptError, EIllegalParameter, EDecryptError, + 1, "error decrypting message"}, + {EExportRestriction, EHandshakeFailure, EExportRestriction, + 1, "export restriction violated"}, + {EProtocolVersion, EIllegalParameter, EProtocolVersion, + 1, "protocol version not supported"}, + {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, + 1, "stronger security routines required"}, + {EInternalError, EHandshakeFailure, EInternalError, + 1, "internal error"}, + {EUserCanceled, ECloseNotify, EUserCanceled, + 0, "handshake canceled by user"}, + {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, + 0, "renegotiation not supported"}, + {-1}, +}; + static Lock dslock; static int dshiwat; static int maxdstate = 128; @@ -124,6 +185,7 @@ static char *hashalgs; enum { +//ZZZ Maxdmsg= 1<<16, Maxdstate= 64 }; @@ -159,9 +221,11 @@ static void put24(uchar *p, int); static void put16(uchar *p, int); static u32int get32(uchar *p); static int get16(uchar *p); -static void tlsAlert(TlsRec *tr, int err); -static void tlsError(TlsRec *tr, int err, char *msg, ...); -#pragma varargck argpos tlsError 3 +static void tlsSetState(TlsRec *tr, int newstate); +static void rcvAlert(TlsRec *tr, int err); +static void sendAlert(TlsRec *tr, int err); +static void rcvError(TlsRec *tr, int err, char *msg, ...); +#pragma varargck argpos rcvError 3 static char *tlsnames[] = { [Qclonus] "clone", @@ -373,7 +437,8 @@ tlsopen(Chan *c, int omode) qlock(&tr->in.io); if(tr->handq != nil) error(Einuse); - tr->handq = qopen(MaxRecLen, 0, nil, nil); +//ZZZ what is the correct buffering here? + tr->handq = qopen(2 * MaxRecLen, 0, nil, nil); if(tr->handq == nil) error("can't allocate handshake queue"); qunlock(&tr->in.io); @@ -598,13 +663,14 @@ tlsrecread(TlsRec *tr) ver = get16(header+1); len = get16(header+3); if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion)) - tlsError(tr, EProtocolVersion, "invalid version in record layer"); + rcvError(tr, EProtocolVersion, "invalid version in record layer"); if(len <= 0) - tlsError(tr, EIllegalParameter, "invalid length in record layer"); + rcvError(tr, EIllegalParameter, "invalid length in record layer"); if(len > MaxRecLen) - tlsError(tr, ERecordOverflow, "record message too long"); + rcvError(tr, ERecordOverflow, "record message too long"); ensure(tr, &tr->unprocessed, len); nconsumed = 0; + poperror(); /* * If an Eintr happens after this, we'll get out of sync. @@ -616,7 +682,7 @@ tlsrecread(TlsRec *tr) in = &tr->in; if(waserror()){ -//ZZZ kill the connection +//ZZZ kill the connection? qunlock(&in->seclock); if(b != nil) freeb(b); @@ -627,7 +693,7 @@ tlsrecread(TlsRec *tr) p = b->rp; if(in->sec != nil) { if(len <= in->sec->maclen) - tlsError(tr, EDecodeError, "record message too short for mac"); + rcvError(tr, EDecodeError, "record message too short for mac"); rc4(&in->sec->rc4, p, len); len -= in->sec->maclen; @@ -637,58 +703,65 @@ tlsrecread(TlsRec *tr) in->seq++; (*tr->packMac)(in->sec, in->sec->mackey, seq, header, p, len, hmac); if(memcmp(hmac, p+len, in->sec->maclen) != 0) - tlsError(tr, EBadRecordMac, "record mac mismatch"); + rcvError(tr, EBadRecordMac, "record mac mismatch"); } - qunlock(&tr->in.seclock); + qunlock(&in->seclock); poperror(); if(len <= 0) - tlsError(tr, EDecodeError, "runt record message"); + rcvError(tr, EDecodeError, "runt record message"); switch(type) { default: - tlsError(tr, EIllegalParameter, "invalid record message 0x%x", type); + rcvError(tr, EIllegalParameter, "invalid record message 0x%x", type); return; case RChangeCipherSpec: if(len != 1 || p[0] != 1) - tlsError(tr, EHandshakeFailure, "invalid change cipher spec"); + rcvError(tr, EDecodeError, "invalid change cipher spec"); qlock(&in->seclock); if(in->new == nil){ qunlock(&in->seclock); - tlsError(tr, EUnexpectedMessage, "unexpected change cipher spec"); + rcvError(tr, EUnexpectedMessage, "unexpected change cipher spec"); } - free(tr->in.sec); - tr->in.sec = tr->in.new; - tr->in.new = nil; - tr->in.seq = 0; + free(in->sec); + in->sec = in->new; + in->new = nil; + in->seq = 0; qunlock(&in->seclock); break; case RAlert: if(len != 2) - tlsError(tr, EDecodeError, "invalid alert"); + rcvError(tr, EDecodeError, "invalid alert"); if(p[0] == 1) { if(p[1] == ECloseNotify) { - tlsError(tr, ECloseNotify, "remote close"); + rcvError(tr, ECloseNotify, "remote close"); tlsSetState(tr, SRemoteClosed); } + /* + * ignore EUserCancelled, it's meaningless + * need to handle ENoRenegotiation + */ } else { - tlsSetState(tr, SError); - tlsAlert(tr, p[1]); + rcvAlert(tr, p[1]); } break; case RHandshake: /* * don't worry about dropping the block - * qbwrite always queue it even if flow controlled and interrupted. + * qbwrite always queues even if flow controlled and interrupted. + * + * if there isn't any handshaker, ignore the request, + * but notify the other side we are doing so. */ if(tr->handq != nil){ qbwrite(tr->handq, b); b = nil; - } + }else if(tr->verset && tr->version != SSL3Version) + sendAlert(tr, ENoRenegotiation); break; case RApplication: //ZZZ race on state if(tr->state != SOpen) - tlsError(tr, EUnexpectedMessage, "application message received before handshake completed"); + rcvError(tr, EUnexpectedMessage, "application message received before handshake completed"); tr->processed = b; b = nil; break; @@ -770,6 +843,7 @@ tlsread(Chan *c, void *a, long n, vlong off) snprint(buf, sizeof(buf), "%lud", CONV(c->qid)); return readstr(offset, a, n, buf); case Qdata: + case Qhand: b = tlsbread(c, n, offset); break; case Qencalgs: @@ -914,8 +988,8 @@ tlsbwrite(Chan *c, Block *b, ulong offset) return devbwrite(c, b, offset); case Qhand: //ZZZ race setting state - if(tr->state != SHandshake && tr->state != SOpen) - error(Ebadusefd); +// if(tr->state != SHandshake && tr->state != SOpen) +// error(Ebadusefd); tlsrecwrite(tr, RHandshake, b); break; case Qdata: @@ -948,7 +1022,7 @@ initmd5key(Hashalg *ha, int version, Secret *s, uchar *p) memmove(s->mackey, p, ha->maclen); } -Hashalg hashtab[] = +static Hashalg hashtab[] = { { "clear" }, { "md5", MD5dlen, initmd5key, }, @@ -982,7 +1056,7 @@ initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *) setupRC4state(&s->rc4, p, ea->keylen); } -Encalg encrypttab[] = +static Encalg encrypttab[] = { { "clear" }, { "rc4_128", 128/8, 0, initRC4key, }, @@ -1007,11 +1081,12 @@ tlswrite(Chan *c, void *a, long n, vlong off) Encalg *ea; Hashalg *ha; TlsRec *volatile tr; + Secret *tos, *toc; Block *volatile b; Cmdbuf *volatile cb; int m; - char *p, *e, buf[128]; - uchar *x; + char *p, *e; + uchar *volatile x; ulong offset = off; tr = dstate[CONV(c->qid)]; @@ -1049,7 +1124,7 @@ tlswrite(Chan *c, void *a, long n, vlong off) return -1; } - cb = parsecmd(buf, n); + cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); @@ -1072,11 +1147,12 @@ tlswrite(Chan *c, void *a, long n, vlong off) error("usage: fd n version"); if(tr->c != nil) error(Einuse); - n = strtol(cb->f[2], nil, 0); - if(n < MinProtoVersion || n > MinProtoVersion) + m = strtol(cb->f[2], nil, 0); + if(m < MinProtoVersion || m > MaxProtoVersion) error("unsupported version"); tr->c = buftochan(cb->f[1]); - tr->version = n; + tr->version = m; + tlsSetState(tr, SHandshake); }else if(strcmp(cb->f[0], "version") == 0){ if(cb->nf != 2) error("usage: version n"); @@ -1084,49 +1160,63 @@ tlswrite(Chan *c, void *a, long n, vlong off) error("must set fd before version"); if(tr->verset) error("version already set"); - n = strtol(cb->f[1], nil, 0); - if(n == SSL3Version) + m = strtol(cb->f[1], nil, 0); + if(m == SSL3Version) tr->packMac = sslPackMac; - else if(n == TLSVersion) + else if(m == TLSVersion) tr->packMac = tlsPackMac; else error("unsupported version"); tr->verset = 1; - tr->version = n; + tr->version = m; + }else if(strcmp(cb->f[0], "opened") == 0){ + if(cb->nf != 1) + error("usage: opened"); + tlsSetState(tr, SOpen); }else if(strcmp(cb->f[0], "alert") == 0){ if(cb->nf != 2) error("usage: alert n"); if(tr->c == nil) error("must set fd before sending alerts"); + m = strtol(cb->f[1], nil, 0); + + qunlock(&tr->in.seclock); + qunlock(&tr->out.seclock); + poperror(); + free(cb); + poperror(); - n = strtol(cb->f[1], nil, 0); + sendAlert(tr, m); - tlsError(tr, n); - b = allocb(2); -//ZZZ need to check for fatal error - *b->wp++ = 1; - *b->wp++ = n; - tlsrecwrite(tr, RAlert, b); - freeb(b); -//ZZZ race on state - tlsSetState(tr, SError); + return n; }else if(strcmp(cb->f[0], "changecipher") == 0){ if(cb->nf != 1) error("usage: changecipher"); if(tr->out.new == nil) error("can't change cipher spec without setting secret"); + toc = tr->out.new; + tr->out.new = nil; + +//ZZZ minor race; worth fixing? + qunlock(&tr->in.seclock); + qunlock(&tr->out.seclock); + poperror(); + free(cb); + poperror(); + b = allocb(1); *b->wp++ = 1; tlsrecwrite(tr, RChangeCipherSpec, b); - freeb(b); + qlock(&tr->out.seclock); free(tr->out.sec); - tr->out.sec = tr->out.new; - tr->out.new = nil; + tr->out.sec = toc; + qunlock(&tr->out.seclock); + return n; }else if(strcmp(cb->f[0], "secret") == 0){ - if(cb->nf != 4) - error("usage: secret hashalg encalg secretdata"); + if(cb->nf != 5) + error("usage: secret hashalg encalg isclient secretdata"); if(tr->c == nil || !tr->verset) error("must set fd and version before secrets"); @@ -1142,25 +1232,33 @@ tlswrite(Chan *c, void *a, long n, vlong off) ha = parsehashalg(cb->f[1]); ea = parseencalg(cb->f[2]); - m = (strlen(cb->f[3])*3)/2; + p = cb->f[4]; + m = (strlen(p)*3)/2; x = smalloc(m); if(waserror()){ free(x); - poperror(); + nexterror(); } - m = dec64(x, m, cb->f[3], strlen(cb->f[3])); - if(m != 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen) - error("bad secret data length"); + m = dec64(x, m, p, strlen(p)); + if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen) + error("not enough secret data provided"); - tr->out.new = smalloc(sizeof(Secret)); - tr->in.new = smalloc(sizeof(Secret)); + tos = smalloc(sizeof(Secret)); + toc = smalloc(sizeof(Secret)); if(ha->initkey){ - (*ha->initkey)(ha, tr->version, tr->in.new, &x[0]); - (*ha->initkey)(ha, tr->version, tr->out.new, &x[ha->maclen]); + (*ha->initkey)(ha, tr->version, tos, &x[0]); + (*ha->initkey)(ha, tr->version, toc, &x[ha->maclen]); } if(ea->initkey){ - (*ea->initkey)(ea, tr->in.new, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]); - (*ea->initkey)(ea, tr->out.new, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]); + (*ea->initkey)(ea, tos, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]); + (*ea->initkey)(ea, toc, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]); + } + if(strtol(cb->f[3], nil, 0) == 0){ + tr->in.new = tos; + tr->out.new = toc; + }else{ + tr->in.new = toc; + tr->out.new = tos; } free(x); @@ -1254,6 +1352,76 @@ buftochan(char *p) return c; } +static void +sendAlert(TlsRec *tr, int err) +{ + Block *b; + int i, fatal; + + fatal = 1; + for(i=0; i < nelem(tlserrs); i++) { + if(tlserrs[i].err == err) { + if(tr->version == SSL3Version) + err = tlserrs[i].sslerr; + else + err = tlserrs[i].tlserr; + fatal = tlserrs[i].fatal; + break; + } + } + + b = allocb(2); + *b->wp++ = fatal + 1; + *b->wp++ = err; + tlsrecwrite(tr, RAlert, b); +//ZZZ race on state + if(fatal) + tlsSetState(tr, SError); +} + +static void +rcvAlert(TlsRec *tr, int err) +{ + char *s; + int i, fatal; + + s = "unknown error"; + fatal = 1; + for(i=0; i < nelem(tlserrs); i++){ + if(tlserrs[i].err == err){ + s = tlserrs[i].msg; + fatal = tlserrs[i].fatal; + break; + } + } +//ZZZ need to kill session if fatal error + if(fatal) + tlsSetState(tr, SError); + error(s); +} + +static void +rcvError(TlsRec *tr, int err, char *fmt, ...) +{ + char msg[ERRLEN]; + va_list arg; + + sendAlert(tr, err); + va_start(arg, fmt); + strcpy(msg, "tls local %s"); + doprint(strchr(msg, '\0'), msg+sizeof(msg), fmt, arg); + va_end(arg); + error(msg); +} + +static void +tlsSetState(TlsRec *tr, int newstate) +{ + lock(&tr->statelk); + tr->state = newstate; + unlock(&tr->statelk); +} + /* hand up a digest connection */ static void tlshangup(TlsRec *s)