diff options
Diffstat (limited to 'usr.sbin/ppp/hdlc.c')
-rw-r--r-- | usr.sbin/ppp/hdlc.c | 480 |
1 files changed, 261 insertions, 219 deletions
diff --git a/usr.sbin/ppp/hdlc.c b/usr.sbin/ppp/hdlc.c index 4854811543de..a6f1c25133ae 100644 --- a/usr.sbin/ppp/hdlc.c +++ b/usr.sbin/ppp/hdlc.c @@ -17,12 +17,15 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: hdlc.c,v 1.29 1998/03/12 02:23:38 brian Exp $ + * $Id: hdlc.c,v 1.28.2.37 1998/05/21 01:26:07 brian Exp $ * * TODO: */ -#include <sys/param.h> +#include <sys/types.h> #include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <sys/un.h> #include <stdio.h> #include <string.h> @@ -34,50 +37,30 @@ #include "defs.h" #include "timer.h" #include "fsm.h" +#include "lqr.h" #include "hdlc.h" #include "lcpproto.h" +#include "iplist.h" +#include "throughput.h" +#include "slcompress.h" #include "ipcp.h" #include "ip.h" #include "vjcomp.h" +#include "auth.h" #include "pap.h" #include "chap.h" #include "lcp.h" #include "async.h" -#include "lqr.h" -#include "loadalias.h" -#include "vars.h" -#include "modem.h" #include "ccp.h" - -static struct hdlcstat { - int badfcs; - int badaddr; - int badcommand; - int unknownproto; -} HdlcStat; - -static u_int32_t ifOutPackets; -static u_int32_t ifOutOctets; -static u_int32_t ifOutLQRs; - -static struct protostat { - u_short number; - const char *name; - u_long in_count; - u_long out_count; -} ProtocolStat[] = { - { PROTO_IP, "IP" }, - { PROTO_VJUNCOMP, "VJ_UNCOMP" }, - { PROTO_VJCOMP, "VJ_COMP" }, - { PROTO_COMPD, "COMPD" }, - { PROTO_LCP, "LCP" }, - { PROTO_IPCP, "IPCP" }, - { PROTO_CCP, "CCP" }, - { PROTO_PAP, "PAP" }, - { PROTO_LQR, "LQR" }, - { PROTO_CHAP, "CHAP" }, - { 0, "Others" } -}; +#include "link.h" +#include "descriptor.h" +#include "physical.h" +#include "prompt.h" +#include "chat.h" +#include "mp.h" +#include "datalink.h" +#include "filter.h" +#include "bundle.h" static u_short const fcstab[256] = { /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, @@ -114,14 +97,11 @@ static u_short const fcstab[256] = { /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -u_char EscMap[33]; - void -HdlcInit() +hdlc_Init(struct hdlc *hdlc, struct lcp *lcp) { - ifOutOctets = 0; - ifOutPackets = 0; - ifOutLQRs = 0; + memset(hdlc, '\0', sizeof(struct hdlc)); + hdlc->lqm.owner = lcp; } /* @@ -129,7 +109,7 @@ HdlcInit() * 2.27 for further details. */ inline u_short -HdlcFcs(u_short fcs, u_char * cp, int len) +hdlc_Fcs(u_short fcs, u_char * cp, int len) { while (len--) fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; @@ -142,7 +122,7 @@ HdlcFcsBuf(u_short fcs, struct mbuf *m) int len; u_char *pos, *end; - len = plength(m); + len = mbuf_Length(m); pos = MBUF_CTOP(m); end = pos + m->cnt; while (len--) { @@ -157,28 +137,22 @@ HdlcFcsBuf(u_short fcs, struct mbuf *m) } void -HdlcOutput(int pri, u_short proto, struct mbuf * bp) +hdlc_Output(struct link *l, int pri, u_short proto, struct mbuf *bp) { + struct physical *p = link2physical(l); struct mbuf *mhp, *mfcs; - struct protostat *statp; - struct lqrdata *lqr; u_char *cp; u_short fcs; - if ((proto & 0xfff1) == 0x21) /* Network Layer protocol */ - if (CcpFsm.state == ST_OPENED) - if (CcpOutput(pri, proto, bp)) - return; - - if (DEV_IS_SYNC) + if (!p || physical_IsSync(p)) mfcs = NULL; else - mfcs = mballoc(2, MB_HDLCOUT); + mfcs = mbuf_Alloc(2, MB_HDLCOUT); - mhp = mballoc(4, MB_HDLCOUT); + mhp = mbuf_Alloc(4, MB_HDLCOUT); mhp->cnt = 0; cp = MBUF_CTOP(mhp); - if (proto == PROTO_LCP || LcpInfo.his_acfcomp == 0) { + if (p && (proto == PROTO_LCP || l->lcp.his_acfcomp == 0)) { *cp++ = HDLC_ADDR; *cp++ = HDLC_UI; mhp->cnt += 2; @@ -187,7 +161,7 @@ HdlcOutput(int pri, u_short proto, struct mbuf * bp) /* * If possible, compress protocol field. */ - if (LcpInfo.his_protocomp && (proto & 0xff00) == 0) { + if (l->lcp.his_protocomp && (proto & 0xff00) == 0) { *cp++ = proto; mhp->cnt++; } else { @@ -195,41 +169,60 @@ HdlcOutput(int pri, u_short proto, struct mbuf * bp) *cp = proto & 0377; mhp->cnt += 2; } + mhp->next = bp; + + if (!p) { + /* + * This is where we multiplex the data over our available physical + * links. We don't frame our logical link data. Instead we wait + * for the logical link implementation to chop our data up and pile + * it into the physical links by re-calling this function with the + * encapsulated fragments. + */ + link_Output(l, pri, mhp); + return; + } + + /* Tack mfcs onto the end, then set bp back to the start of the data */ while (bp->next != NULL) bp = bp->next; bp->next = mfcs; bp = mhp->next; - lqr = &MyLqrData; - lqr->PeerOutPackets = ifOutPackets++; - ifOutOctets += plength(mhp) + 1; - lqr->PeerOutOctets = ifOutOctets; + p->hdlc.lqm.OutOctets += mbuf_Length(mhp) + 1; + p->hdlc.lqm.OutPackets++; if (proto == PROTO_LQR) { - lqr->MagicNumber = LcpInfo.want_magic; - lqr->LastOutLQRs = HisLqrData.PeerOutLQRs; - lqr->LastOutPackets = HisLqrData.PeerOutPackets; - lqr->LastOutOctets = HisLqrData.PeerOutOctets; - lqr->PeerInLQRs = HisLqrSave.SaveInLQRs; - lqr->PeerInPackets = HisLqrSave.SaveInPackets; - lqr->PeerInDiscards = HisLqrSave.SaveInDiscards; - lqr->PeerInErrors = HisLqrSave.SaveInErrors; - lqr->PeerInOctets = HisLqrSave.SaveInOctets; - if (HisLqrData.LastOutLQRs == ifOutLQRs) { + /* Overwrite the entire packet */ + struct lqrdata lqr; + + lqr.MagicNumber = p->link.lcp.want_magic; + lqr.LastOutLQRs = p->hdlc.lqm.lqr.peer.PeerOutLQRs; + lqr.LastOutPackets = p->hdlc.lqm.lqr.peer.PeerOutPackets; + lqr.LastOutOctets = p->hdlc.lqm.lqr.peer.PeerOutOctets; + lqr.PeerInLQRs = p->hdlc.lqm.lqr.SaveInLQRs; + lqr.PeerInPackets = p->hdlc.lqm.SaveInPackets; + lqr.PeerInDiscards = p->hdlc.lqm.SaveInDiscards; + lqr.PeerInErrors = p->hdlc.lqm.SaveInErrors; + lqr.PeerInOctets = p->hdlc.lqm.SaveInOctets; + lqr.PeerOutPackets = p->hdlc.lqm.OutPackets; + lqr.PeerOutOctets = p->hdlc.lqm.OutOctets; + if (p->hdlc.lqm.lqr.peer.LastOutLQRs == p->hdlc.lqm.lqr.OutLQRs) { /* * only increment if it's the first time or we've got a reply * from the last one */ - lqr->PeerOutLQRs = ++ifOutLQRs; - LqrDump("LqrOutput", lqr); + lqr.PeerOutLQRs = ++p->hdlc.lqm.lqr.OutLQRs; + lqr_Dump(l->name, "Output", &lqr); } else { - lqr->PeerOutLQRs = ifOutLQRs; - LqrDump("LqrOutput (again)", lqr); + lqr.PeerOutLQRs = p->hdlc.lqm.lqr.OutLQRs; + lqr_Dump(l->name, "Output (again)", &lqr); } - LqrChangeOrder(lqr, (struct lqrdata *) (MBUF_CTOP(bp))); + lqr_ChangeOrder(&lqr, (struct lqrdata *)MBUF_CTOP(bp)); } - if (!DEV_IS_SYNC) { + + if (mfcs) { mfcs->cnt = 0; fcs = HdlcFcsBuf(INITFCS, mhp); fcs = ~fcs; @@ -238,18 +231,16 @@ HdlcOutput(int pri, u_short proto, struct mbuf * bp) *cp++ = fcs >> 8; mfcs->cnt = 2; } - LogDumpBp(LogHDLC, "HdlcOutput", mhp); - for (statp = ProtocolStat; statp->number; statp++) - if (statp->number == proto) - break; - statp->out_count++; - LogPrintf(LogDEBUG, "HdlcOutput: proto = 0x%04x\n", proto); + log_DumpBp(LogHDLC, "hdlc_Output", mhp); + + link_ProtocolRecord(l, proto, PROTO_OUT); + log_Printf(LogDEBUG, "hdlc_Output: proto = 0x%04x\n", proto); - if (DEV_IS_SYNC) - ModemOutput(pri, mhp); + if (physical_IsSync(p)) + link_Output(l, pri, mhp); /* Send it raw */ else - AsyncOutput(pri, mhp, proto); + async_Output(pri, mhp, proto, p); } /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ @@ -365,8 +356,8 @@ static struct { #define NPROTOCOLS (sizeof protocols/sizeof protocols[0]) -static const char * -Protocol2Nam(u_short proto) +const char * +hdlc_Protocol2Nam(u_short proto) { int f; @@ -378,209 +369,260 @@ Protocol2Nam(u_short proto) return "unrecognised protocol"; } -static void -DecodePacket(u_short proto, struct mbuf * bp) +void +hdlc_DecodePacket(struct bundle *bundle, u_short proto, struct mbuf * bp, + struct link *l) { + struct physical *p = link2physical(l); u_char *cp; - LogPrintf(LogDEBUG, "DecodePacket: proto = 0x%04x\n", proto); + log_Printf(LogDEBUG, "DecodePacket: proto = 0x%04x\n", proto); - /* - * If proto isn't PROTO_COMPD, we still want to pass it to the - * decompression routines so that the dictionary's updated - */ - if (CcpFsm.state == ST_OPENED) { - if (proto == PROTO_COMPD) { - if ((bp = CompdInput(&proto, bp)) == NULL) - return; - } else if ((proto & 0xfff1) == 0x21) /* Network Layer protocol */ - CcpDictSetup(proto, bp); - } + /* decompress everything. CCP needs uncompressed data too */ + if ((bp = ccp_Decompress(&l->ccp, &proto, bp)) == NULL) + return; switch (proto) { case PROTO_LCP: - LcpInput(bp); + lcp_Input(&l->lcp, bp); break; case PROTO_PAP: - PapInput(bp); + if (p) + pap_Input(bundle, bp, p); + else { + log_Printf(LogERROR, "DecodePacket: PAP: Not a physical link !\n"); + mbuf_Free(bp); + } break; case PROTO_LQR: - HisLqrSave.SaveInLQRs++; - LqrInput(bp); + if (p) { + p->hdlc.lqm.lqr.SaveInLQRs++; + lqr_Input(p, bp); + } else { + log_Printf(LogERROR, "DecodePacket: LQR: Not a physical link !\n"); + mbuf_Free(bp); + } break; case PROTO_CHAP: - ChapInput(bp); + if (p) + chap_Input(bundle, bp, p); + else { + log_Printf(LogERROR, "DecodePacket: CHAP: Not a physical link !\n"); + mbuf_Free(bp); + } break; case PROTO_VJUNCOMP: case PROTO_VJCOMP: - bp = VjCompInput(bp, proto); - if (bp == NULL) { + bp = vj_Input(&bundle->ncp.ipcp, bp, proto); + if (bp == NULL) break; - } /* fall down */ case PROTO_IP: - IpInput(bp); + ip_Input(bundle, bp); break; case PROTO_IPCP: - IpcpInput(bp); + ipcp_Input(&bundle->ncp.ipcp, bundle, bp); break; case PROTO_CCP: - CcpInput(bp); + ccp_Input(&l->ccp, bundle, bp); break; + case PROTO_MP: + if (bundle->ncp.mp.active) { + if (p) + mp_Input(&bundle->ncp.mp, bp, p); + else { + log_Printf(LogERROR, "DecodePacket: MP inside MP ?!\n"); + mbuf_Free(bp); + } + break; + } + /* Fall through */ default: - LogPrintf(LogPHASE, "Unknown protocol 0x%04x (%s)\n", - proto, Protocol2Nam(proto)); + log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n", + proto == PROTO_MP ? "Unexpected" : "Unknown", + proto, hdlc_Protocol2Nam(proto)); bp->offset -= 2; bp->cnt += 2; cp = MBUF_CTOP(bp); - LcpSendProtoRej(cp, bp->cnt); - HisLqrSave.SaveInDiscards++; - HdlcStat.unknownproto++; - pfree(bp); - break; - } -} - -int -ReportProtStatus(struct cmdargs const *arg) -{ - struct protostat *statp; - int cnt; - - statp = ProtocolStat; - statp--; - cnt = 0; - fprintf(VarTerm, " Protocol in out Protocol in out\n"); - do { - statp++; - fprintf(VarTerm, " %-9s: %8lu, %8lu", - statp->name, statp->in_count, statp->out_count); - if (++cnt == 2) { - fprintf(VarTerm, "\n"); - cnt = 0; + lcp_SendProtoRej(&l->lcp, cp, bp->cnt); + if (p) { + p->hdlc.lqm.SaveInDiscards++; + p->hdlc.stats.unknownproto++; } - } while (statp->number); - if (cnt) - fprintf(VarTerm, "\n"); - return (0); -} - -int -ReportHdlcStatus(struct cmdargs const *arg) -{ - struct hdlcstat *hp = &HdlcStat; - - if (VarTerm) { - fprintf(VarTerm, "HDLC level errors\n\n"); - fprintf(VarTerm, "FCS: %u ADDR: %u COMMAND: %u PROTO: %u\n", - hp->badfcs, hp->badaddr, hp->badcommand, hp->unknownproto); + mbuf_Free(bp); + break; } - return 0; } -static struct hdlcstat laststat; - -void -HdlcErrorCheck() +static int +hdlc_GetProto(const u_char *cp, u_short *proto) { - struct hdlcstat *hp = &HdlcStat; - struct hdlcstat *op = &laststat; - - if (memcmp(hp, op, sizeof laststat)) { - LogPrintf(LogPHASE, "HDLC errors -> FCS: %u ADDR: %u COMD: %u PROTO: %u\n", - hp->badfcs - op->badfcs, hp->badaddr - op->badaddr, - hp->badcommand - op->badcommand, hp->unknownproto - op->unknownproto); + *proto = *cp; + if (!(*proto & 1)) { + *proto = (*proto << 8) | cp[1]; + return 2; } - laststat = HdlcStat; + return 1; } void -HdlcInput(struct mbuf * bp) +hdlc_Input(struct bundle *bundle, struct mbuf * bp, struct physical *physical) { u_short fcs, proto; u_char *cp, addr, ctrl; - struct protostat *statp; + int n; - LogDumpBp(LogHDLC, "HdlcInput:", bp); - if (DEV_IS_SYNC) + log_DumpBp(LogHDLC, "hdlc_Input:", bp); + if (physical_IsSync(physical)) fcs = GOODFCS; else - fcs = HdlcFcs(INITFCS, MBUF_CTOP(bp), bp->cnt); - HisLqrSave.SaveInOctets += bp->cnt + 1; + fcs = hdlc_Fcs(INITFCS, MBUF_CTOP(bp), bp->cnt); + physical->hdlc.lqm.SaveInOctets += bp->cnt + 1; - LogPrintf(LogDEBUG, "HdlcInput: fcs = %04x (%s)\n", - fcs, (fcs == GOODFCS) ? "good" : "bad"); + log_Printf(LogDEBUG, "%s: hdlc_Input: fcs = %04x (%s)\n", + physical->link.name, fcs, (fcs == GOODFCS) ? "good" : "BAD!"); if (fcs != GOODFCS) { - HisLqrSave.SaveInErrors++; - LogPrintf(LogDEBUG, "HdlcInput: Bad FCS\n"); - HdlcStat.badfcs++; - pfree(bp); + physical->hdlc.lqm.SaveInErrors++; + physical->hdlc.stats.badfcs++; + mbuf_Free(bp); return; } - if (!DEV_IS_SYNC) + if (!physical_IsSync(physical)) bp->cnt -= 2; /* discard FCS part */ if (bp->cnt < 2) { /* XXX: raise this bar ? */ - pfree(bp); + mbuf_Free(bp); return; } cp = MBUF_CTOP(bp); - if (!LcpInfo.want_acfcomp) { - - /* - * We expect that packet is not compressed. - */ + if (!physical->link.lcp.want_acfcomp) { + /* We expect the packet not to be compressed */ addr = *cp++; if (addr != HDLC_ADDR) { - HisLqrSave.SaveInErrors++; - HdlcStat.badaddr++; - LogPrintf(LogDEBUG, "HdlcInput: addr %02x\n", *cp); - pfree(bp); + physical->hdlc.lqm.SaveInErrors++; + physical->hdlc.stats.badaddr++; + log_Printf(LogDEBUG, "hdlc_Input: addr %02x\n", *cp); + mbuf_Free(bp); return; } ctrl = *cp++; if (ctrl != HDLC_UI) { - HisLqrSave.SaveInErrors++; - HdlcStat.badcommand++; - LogPrintf(LogDEBUG, "HdlcInput: %02x\n", *cp); - pfree(bp); + physical->hdlc.lqm.SaveInErrors++; + physical->hdlc.stats.badcommand++; + log_Printf(LogDEBUG, "hdlc_Input: %02x\n", *cp); + mbuf_Free(bp); return; } bp->offset += 2; bp->cnt -= 2; } else if (cp[0] == HDLC_ADDR && cp[1] == HDLC_UI) { - /* - * We can receive compressed packet, but peer still send uncompressed - * packet to me. + * We can receive compressed packets, but the peer still sends + * uncompressed packets ! */ cp += 2; bp->offset += 2; bp->cnt -= 2; } - if (LcpInfo.want_protocomp) { - proto = 0; - cp--; - do { - cp++; - bp->offset++; - bp->cnt--; - proto = proto << 8; - proto += *cp; - } while (!(proto & 1)); - } else { - proto = *cp++ << 8; - proto |= *cp++; - bp->offset += 2; - bp->cnt -= 2; - } - for (statp = ProtocolStat; statp->number; statp++) - if (statp->number == proto) + n = hdlc_GetProto(cp, &proto); + bp->offset += n; + bp->cnt -= n; + if (!physical->link.lcp.want_protocomp && n == 1) + log_Printf(LogHDLC, "%s: Warning: received a proto-compressed packet !\n", + physical->link.name); + + link_ProtocolRecord(&physical->link, proto, PROTO_IN); + physical->hdlc.lqm.SaveInPackets++; + + hdlc_DecodePacket(bundle, proto, bp, &physical->link); +} + +/* + * Detect a HDLC frame + */ + +static const char *FrameHeaders[] = { + "\176\377\003\300\041", + "\176\377\175\043\300\041", + "\176\177\175\043\100\041", + "\176\175\337\175\043\300\041", + "\176\175\137\175\043\100\041", + NULL, +}; + +u_char * +hdlc_Detect(struct physical *physical, u_char *cp, int n) +{ + const char *fp, **hp; + char *ptr; + + cp[n] = '\0'; /* be sure to null terminate */ + ptr = NULL; + for (hp = FrameHeaders; *hp; hp++) { + fp = *hp; + if (physical_IsSync(physical)) + fp++; + ptr = strstr((char *)cp, fp); /* XXX: cp may have embedded NULs */ + if (ptr) break; - statp->in_count++; - HisLqrSave.SaveInPackets++; + } + return (u_char *)ptr; +} - DecodePacket(proto, bp); +int +hdlc_ReportStatus(struct cmdargs const *arg) +{ + struct hdlc *hdlc = &arg->cx->physical->hdlc; + + prompt_Printf(arg->prompt, "%s HDLC level errors:\n", arg->cx->name); + prompt_Printf(arg->prompt, " Bad Frame Check Sequence fields: %u\n", + hdlc->stats.badfcs); + prompt_Printf(arg->prompt, " Bad address (!= 0x%02x) fields: %u\n", + HDLC_ADDR, hdlc->stats.badaddr); + prompt_Printf(arg->prompt, " Bad command (!= 0x%02x) fields: %u\n", + HDLC_UI, hdlc->stats.badcommand); + prompt_Printf(arg->prompt, " Unrecognised protocol fields: %u\n", + hdlc->stats.unknownproto); + return 0; +} + +static void +hdlc_ReportTime(void *v) +{ + /* Moan about HDLC errors */ + struct hdlc *hdlc = (struct hdlc *)v; + + timer_Stop(&hdlc->ReportTimer); + + if (memcmp(&hdlc->laststats, &hdlc->stats, sizeof hdlc->stats)) { + log_Printf(LogPHASE, + "%s: HDLC errors -> FCS: %u, ADDR: %u, COMD: %u, PROTO: %u\n", + hdlc->lqm.owner->fsm.link->name, + hdlc->stats.badfcs - hdlc->laststats.badfcs, + hdlc->stats.badaddr - hdlc->laststats.badaddr, + hdlc->stats.badcommand - hdlc->laststats.badcommand, + hdlc->stats.unknownproto - hdlc->laststats.unknownproto); + hdlc->laststats = hdlc->stats; + } + + timer_Start(&hdlc->ReportTimer); +} + +void +hdlc_StartTimer(struct hdlc *hdlc) +{ + timer_Stop(&hdlc->ReportTimer); + hdlc->ReportTimer.load = 60 * SECTICKS; + hdlc->ReportTimer.arg = hdlc; + hdlc->ReportTimer.func = hdlc_ReportTime; + hdlc->ReportTimer.name = "hdlc"; + timer_Start(&hdlc->ReportTimer); +} + +void +hdlc_StopTimer(struct hdlc *hdlc) +{ + timer_Stop(&hdlc->ReportTimer); } |