178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD: releng/11.0/usr.sbin/ppp/lqr.c 241496 2012-10-12 22:48:33Z n_hibma $ 296059Samurai */ 3030715Sbrian 3143313Sbrian#include <sys/param.h> 3296582Sbrian 3396582Sbrian#ifdef __FreeBSD__ 3496582Sbrian#include <netinet/in.h> 3596582Sbrian#endif 3636285Sbrian#include <sys/un.h> 3736285Sbrian 3834494Sbrian#include <string.h> 3936285Sbrian#include <termios.h> 4030715Sbrian 4146686Sbrian#include "layer.h" 4230715Sbrian#include "mbuf.h" 4330715Sbrian#include "log.h" 4430715Sbrian#include "defs.h" 4530715Sbrian#include "timer.h" 466059Samurai#include "fsm.h" 4746686Sbrian#include "acf.h" 4846686Sbrian#include "proto.h" 496059Samurai#include "lqr.h" 506059Samurai#include "hdlc.h" 5163484Sbrian#include "lcp.h" 5236285Sbrian#include "async.h" 5336285Sbrian#include "throughput.h" 5436285Sbrian#include "ccp.h" 5536285Sbrian#include "link.h" 5636285Sbrian#include "descriptor.h" 5736285Sbrian#include "physical.h" 5836285Sbrian#include "mp.h" 5936285Sbrian#include "chat.h" 6036285Sbrian#include "auth.h" 6136285Sbrian#include "chap.h" 6236285Sbrian#include "command.h" 6338174Sbrian#include "cbcp.h" 6436285Sbrian#include "datalink.h" 656059Samurai 666059Samuraistruct echolqr { 6732439Sbrian u_int32_t magic; 6832439Sbrian u_int32_t signature; 6932439Sbrian u_int32_t sequence; 706059Samurai}; 716059Samurai 726059Samurai#define SIGNATURE 0x594e4f54 736059Samurai 746059Samuraistatic void 7536285SbrianSendEchoReq(struct lcp *lcp) 766059Samurai{ 7736285Sbrian struct hdlc *hdlc = &link2physical(lcp->fsm.link)->hdlc; 7836285Sbrian struct echolqr echo; 796059Samurai 8036285Sbrian echo.magic = htonl(lcp->want_magic); 8136285Sbrian echo.signature = htonl(SIGNATURE); 8236285Sbrian echo.sequence = htonl(hdlc->lqm.echo.seq_sent); 8336285Sbrian fsm_Output(&lcp->fsm, CODE_ECHOREQ, hdlc->lqm.echo.seq_sent++, 8447695Sbrian (u_char *)&echo, sizeof echo, MB_ECHOOUT); 856059Samurai} 866059Samurai 8746828Sbrianstruct mbuf * 8846828Sbrianlqr_RecvEcho(struct fsm *fp, struct mbuf *bp) 896059Samurai{ 9036285Sbrian struct hdlc *hdlc = &link2physical(fp->link)->hdlc; 9147169Sbrian struct lcp *lcp = fsm2lcp(fp); 9246828Sbrian struct echolqr lqr; 936059Samurai 9461852Sbrian if (m_length(bp) >= sizeof lqr) { 9561852Sbrian m_freem(mbuf_Read(bp, &lqr, sizeof lqr)); 9661852Sbrian bp = NULL; 9747169Sbrian lqr.magic = ntohl(lqr.magic); 9847169Sbrian lqr.signature = ntohl(lqr.signature); 9947169Sbrian lqr.sequence = ntohl(lqr.sequence); 10047169Sbrian 10147169Sbrian /* Tolerate echo replies with either magic number */ 10247169Sbrian if (lqr.magic != 0 && lqr.magic != lcp->his_magic && 10347169Sbrian lqr.magic != lcp->want_magic) { 10447169Sbrian log_Printf(LogWARN, "%s: lqr_RecvEcho: Bad magic: expected 0x%08x," 10547169Sbrian " got 0x%08x\n", fp->link->name, lcp->his_magic, lqr.magic); 10647169Sbrian /* 10747169Sbrian * XXX: We should send a terminate request. But poor implementations may 10847169Sbrian * die as a result. 10947169Sbrian */ 11047169Sbrian } 111241496Sn_hibma if (lqr.signature == SIGNATURE 112241496Sn_hibma || lqr.signature == lcp->want_magic) { /* some implementations return the wrong magic */ 11336285Sbrian /* careful not to update lqm.echo.seq_recv with older values */ 11447169Sbrian if ((hdlc->lqm.echo.seq_recv > (u_int32_t)0 - 5 && lqr.sequence < 5) || 11536285Sbrian (hdlc->lqm.echo.seq_recv <= (u_int32_t)0 - 5 && 11647169Sbrian lqr.sequence > hdlc->lqm.echo.seq_recv)) 11747169Sbrian hdlc->lqm.echo.seq_recv = lqr.sequence; 11836285Sbrian } else 11937210Sbrian log_Printf(LogWARN, "lqr_RecvEcho: Got sig 0x%08lx, not 0x%08lx !\n", 12052304Sbrian (u_long)lqr.signature, (u_long)SIGNATURE); 12136285Sbrian } else 122134833Smarcel log_Printf(LogWARN, "lqr_RecvEcho: Got packet size %zd, expecting %ld !\n", 12354912Sbrian m_length(bp), (long)sizeof(struct echolqr)); 12446828Sbrian return bp; 1256059Samurai} 1266059Samurai 1276059Samuraivoid 12846828Sbrianlqr_ChangeOrder(struct lqrdata *src, struct lqrdata *dst) 1296059Samurai{ 13037177Sbrian u_int32_t *sp, *dp; 131134789Sbrian unsigned n; 1326059Samurai 13337177Sbrian sp = (u_int32_t *) src; 13437177Sbrian dp = (u_int32_t *) dst; 13546686Sbrian for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_int32_t); n++, sp++, dp++) 13646686Sbrian *dp = ntohl(*sp); 1376059Samurai} 1386059Samurai 1396059Samuraistatic void 14036285SbrianSendLqrData(struct lcp *lcp) 1416059Samurai{ 1426059Samurai struct mbuf *bp; 14347695Sbrian int extra; 1446059Samurai 14547695Sbrian extra = proto_WrapperOctets(lcp, PROTO_LQR) + 14647695Sbrian acf_WrapperOctets(lcp, PROTO_LQR); 14754912Sbrian bp = m_get(sizeof(struct lqrdata) + extra, MB_LQROUT); 14854912Sbrian bp->m_len -= extra; 14954912Sbrian bp->m_offset += extra; 150131327Sbrian 151131327Sbrian /* 152131327Sbrian * Send on the highest priority queue. We send garbage - the real data 153131327Sbrian * is written by lqr_LayerPush() where we know how to fill in all the 154131327Sbrian * fields. Note, lqr_LayerPush() ``knows'' that we're pushing onto the 155131327Sbrian * highest priority queue, and factors out packet & octet values from 156131327Sbrian * other queues! 157131327Sbrian */ 15850867Sbrian link_PushPacket(lcp->fsm.link, bp, lcp->fsm.bundle, 15950867Sbrian LINK_QUEUES(lcp->fsm.link) - 1, PROTO_LQR); 16036285Sbrian} 1616059Samurai 16236285Sbrianstatic void 16336285SbrianSendLqrReport(void *v) 16436285Sbrian{ 16536285Sbrian struct lcp *lcp = (struct lcp *)v; 16636285Sbrian struct physical *p = link2physical(lcp->fsm.link); 16736285Sbrian 16836285Sbrian timer_Stop(&p->hdlc.lqm.timer); 16936285Sbrian 17036285Sbrian if (p->hdlc.lqm.method & LQM_LQR) { 17136285Sbrian if (p->hdlc.lqm.lqr.resent > 5) { 17236285Sbrian /* XXX: Should implement LQM strategy */ 17336285Sbrian log_Printf(LogPHASE, "%s: ** Too many LQR packets lost **\n", 17436285Sbrian lcp->fsm.link->name); 17536285Sbrian log_Printf(LogLQM, "%s: Too many LQR packets lost\n", 17636285Sbrian lcp->fsm.link->name); 17736285Sbrian p->hdlc.lqm.method = 0; 17837007Sbrian datalink_Down(p->dl, CLOSE_NORMAL); 1796059Samurai } else { 18036285Sbrian SendLqrData(lcp); 18136285Sbrian p->hdlc.lqm.lqr.resent++; 1826059Samurai } 18336285Sbrian } else if (p->hdlc.lqm.method & LQM_ECHO) { 18436285Sbrian if ((p->hdlc.lqm.echo.seq_sent > 5 && 18536285Sbrian p->hdlc.lqm.echo.seq_sent - 5 > p->hdlc.lqm.echo.seq_recv) || 18636285Sbrian (p->hdlc.lqm.echo.seq_sent <= 5 && 18736285Sbrian p->hdlc.lqm.echo.seq_sent > p->hdlc.lqm.echo.seq_recv + 5)) { 188138799Sbrian log_Printf(LogPHASE, "%s: ** Too many LCP ECHO packets lost **\n", 18936285Sbrian lcp->fsm.link->name); 190138799Sbrian log_Printf(LogLQM, "%s: Too many LCP ECHO packets lost\n", 19136285Sbrian lcp->fsm.link->name); 19236285Sbrian p->hdlc.lqm.method = 0; 19337007Sbrian datalink_Down(p->dl, CLOSE_NORMAL); 1946059Samurai } else 19536285Sbrian SendEchoReq(lcp); 1966059Samurai } 19736285Sbrian if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load) 19836285Sbrian timer_Start(&p->hdlc.lqm.timer); 1996059Samurai} 2006059Samurai 20146686Sbrianstruct mbuf * 202134789Sbrianlqr_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp) 2036059Samurai{ 20446686Sbrian struct physical *p = link2physical(l); 20546686Sbrian struct lcp *lcp = p->hdlc.lqm.owner; 2066059Samurai int len; 2076059Samurai 20846686Sbrian if (p == NULL) { 20946686Sbrian log_Printf(LogERROR, "lqr_Input: Not a physical link - dropped\n"); 21054912Sbrian m_freem(bp); 21146686Sbrian return NULL; 21246686Sbrian } 21346686Sbrian 21454912Sbrian len = m_length(bp); 21536285Sbrian if (len != sizeof(struct lqrdata)) 21637210Sbrian log_Printf(LogWARN, "lqr_Input: Got packet size %d, expecting %ld !\n", 21737210Sbrian len, (long)sizeof(struct lqrdata)); 21846686Sbrian else if (!IsAccepted(l->lcp.cfg.lqr) && !(p->hdlc.lqm.method & LQM_LQR)) { 21954912Sbrian bp = m_pullup(proto_Prepend(bp, PROTO_LQR, 0, 0)); 22054912Sbrian lcp_SendProtoRej(lcp, MBUF_CTOP(bp), bp->m_len); 2216059Samurai } else { 22236285Sbrian struct lqrdata *lqr; 2236059Samurai 22454912Sbrian bp = m_pullup(bp); 22536285Sbrian lqr = (struct lqrdata *)MBUF_CTOP(bp); 22646686Sbrian if (ntohl(lqr->MagicNumber) != lcp->his_magic) 22737210Sbrian log_Printf(LogWARN, "lqr_Input: magic 0x%08lx is wrong," 22837210Sbrian " expecting 0x%08lx\n", 22946686Sbrian (u_long)ntohl(lqr->MagicNumber), (u_long)lcp->his_magic); 23036285Sbrian else { 231131327Sbrian struct lqrdata lastlqr; 2326059Samurai 233131327Sbrian memcpy(&lastlqr, &p->hdlc.lqm.lqr.peer, sizeof lastlqr); 23446686Sbrian lqr_ChangeOrder(lqr, &p->hdlc.lqm.lqr.peer); 23546686Sbrian lqr_Dump(l->name, "Input", &p->hdlc.lqm.lqr.peer); 236131327Sbrian /* we have received an LQR from our peer */ 23746686Sbrian p->hdlc.lqm.lqr.resent = 0; 23836285Sbrian 239131327Sbrian /* Snapshot our state when the LQR packet was received */ 240131327Sbrian memcpy(&p->hdlc.lqm.lqr.prevSave, &p->hdlc.lqm.lqr.Save, 241131327Sbrian sizeof p->hdlc.lqm.lqr.prevSave); 242131327Sbrian p->hdlc.lqm.lqr.Save.InLQRs = ++p->hdlc.lqm.lqr.InLQRs; 243131327Sbrian p->hdlc.lqm.lqr.Save.InPackets = p->hdlc.lqm.ifInUniPackets; 244131327Sbrian p->hdlc.lqm.lqr.Save.InDiscards = p->hdlc.lqm.ifInDiscards; 245131327Sbrian p->hdlc.lqm.lqr.Save.InErrors = p->hdlc.lqm.ifInErrors; 246131327Sbrian p->hdlc.lqm.lqr.Save.InOctets = p->hdlc.lqm.lqr.InGoodOctets; 247131327Sbrian 248131327Sbrian lqr_Analyse(&p->hdlc, &lastlqr, &p->hdlc.lqm.lqr.peer); 249131327Sbrian 25036285Sbrian /* 25136285Sbrian * Generate an LQR response if we're not running an LQR timer OR 252131327Sbrian * two successive LQR's PeerInLQRs are the same. 25336285Sbrian */ 254131327Sbrian if (p->hdlc.lqm.timer.load == 0 || !(p->hdlc.lqm.method & LQM_LQR) || 255131327Sbrian (lastlqr.PeerInLQRs && 256131327Sbrian lastlqr.PeerInLQRs == p->hdlc.lqm.lqr.peer.PeerInLQRs)) 25746686Sbrian SendLqrData(lcp); 2586059Samurai } 2596059Samurai } 26054912Sbrian m_freem(bp); 26146686Sbrian return NULL; 2626059Samurai} 2636059Samurai 2646059Samurai/* 2656059Samurai * When LCP is reached to opened state, We'll start LQM activity. 2666059Samurai */ 26736285Sbrianstatic void 26836285Sbrianlqr_Setup(struct lcp *lcp) 2696059Samurai{ 27036285Sbrian struct physical *physical = link2physical(lcp->fsm.link); 271138799Sbrian int period; 2726059Samurai 27336285Sbrian physical->hdlc.lqm.lqr.resent = 0; 27436285Sbrian physical->hdlc.lqm.echo.seq_sent = 0; 27536285Sbrian physical->hdlc.lqm.echo.seq_recv = 0; 27636285Sbrian memset(&physical->hdlc.lqm.lqr.peer, '\0', 27736285Sbrian sizeof physical->hdlc.lqm.lqr.peer); 27828679Sbrian 279138799Sbrian physical->hdlc.lqm.method = lcp->cfg.echo ? LQM_ECHO : 0; 28036285Sbrian if (IsEnabled(lcp->cfg.lqr) && !REJECTED(lcp, TY_QUALPROTO)) 28136285Sbrian physical->hdlc.lqm.method |= LQM_LQR; 28236285Sbrian timer_Stop(&physical->hdlc.lqm.timer); 2836059Samurai 28436285Sbrian physical->hdlc.lqm.lqr.peer_timeout = lcp->his_lqrperiod; 28534494Sbrian if (lcp->his_lqrperiod) 28636285Sbrian log_Printf(LogLQM, "%s: Expecting LQR every %d.%02d secs\n", 28736285Sbrian physical->link.name, lcp->his_lqrperiod / 100, 28836285Sbrian lcp->his_lqrperiod % 100); 28928679Sbrian 290138799Sbrian period = lcp->want_lqrperiod ? 291138799Sbrian lcp->want_lqrperiod : lcp->cfg.lqrperiod * 100; 292138799Sbrian physical->hdlc.lqm.timer.func = SendLqrReport; 293138799Sbrian physical->hdlc.lqm.timer.name = "lqm"; 294138799Sbrian physical->hdlc.lqm.timer.arg = lcp; 295138799Sbrian 296138799Sbrian if (lcp->want_lqrperiod || physical->hdlc.lqm.method & LQM_ECHO) { 29736285Sbrian log_Printf(LogLQM, "%s: Will send %s every %d.%02d secs\n", 298138799Sbrian physical->link.name, lcp->want_lqrperiod ? "LQR" : "LCP ECHO", 299138799Sbrian period / 100, period % 100); 300138799Sbrian physical->hdlc.lqm.timer.load = period * SECTICKS / 100; 3016059Samurai } else { 30236285Sbrian physical->hdlc.lqm.timer.load = 0; 30334494Sbrian if (!lcp->his_lqrperiod) 304138799Sbrian log_Printf(LogLQM, "%s: LQR/LCP ECHO not negotiated\n", 30536285Sbrian physical->link.name); 3066059Samurai } 3076059Samurai} 3086059Samurai 3096059Samuraivoid 31036285Sbrianlqr_Start(struct lcp *lcp) 31113733Sdfr{ 31236285Sbrian struct physical *p = link2physical(lcp->fsm.link); 31336285Sbrian 31436285Sbrian lqr_Setup(lcp); 31536285Sbrian if (p->hdlc.lqm.timer.load) 31636285Sbrian SendLqrReport(lcp); 31713733Sdfr} 31813733Sdfr 31913733Sdfrvoid 32036285Sbrianlqr_reStart(struct lcp *lcp) 3216059Samurai{ 32236285Sbrian struct physical *p = link2physical(lcp->fsm.link); 3236059Samurai 32436285Sbrian lqr_Setup(lcp); 32536285Sbrian if (p->hdlc.lqm.timer.load) 32636285Sbrian timer_Start(&p->hdlc.lqm.timer); 32736285Sbrian} 32836285Sbrian 32936285Sbrianvoid 33036285Sbrianlqr_StopTimer(struct physical *physical) 33136285Sbrian{ 33236285Sbrian timer_Stop(&physical->hdlc.lqm.timer); 33336285Sbrian} 33436285Sbrian 33536285Sbrianvoid 33636285Sbrianlqr_Stop(struct physical *physical, int method) 33736285Sbrian{ 3386059Samurai if (method == LQM_LQR) 33936285Sbrian log_Printf(LogLQM, "%s: Stop sending LQR, Use LCP ECHO instead.\n", 34036285Sbrian physical->link.name); 3416059Samurai if (method == LQM_ECHO) 34236285Sbrian log_Printf(LogLQM, "%s: Stop sending LCP ECHO.\n", 34336285Sbrian physical->link.name); 34436285Sbrian physical->hdlc.lqm.method &= ~method; 34536285Sbrian if (physical->hdlc.lqm.method) 34636285Sbrian SendLqrReport(physical->hdlc.lqm.owner); 3476059Samurai else 34836285Sbrian timer_Stop(&physical->hdlc.lqm.timer); 3496059Samurai} 3506059Samurai 3516059Samuraivoid 35236285Sbrianlqr_Dump(const char *link, const char *message, const struct lqrdata *lqr) 3536059Samurai{ 35436285Sbrian if (log_IsKept(LogLQM)) { 35536285Sbrian log_Printf(LogLQM, "%s: %s:\n", link, message); 35636285Sbrian log_Printf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n", 35726516Sbrian lqr->MagicNumber, lqr->LastOutLQRs); 35836285Sbrian log_Printf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n", 35926516Sbrian lqr->LastOutPackets, lqr->LastOutOctets); 36036285Sbrian log_Printf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n", 36126516Sbrian lqr->PeerInLQRs, lqr->PeerInPackets); 36236285Sbrian log_Printf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n", 36326516Sbrian lqr->PeerInDiscards, lqr->PeerInErrors); 36436285Sbrian log_Printf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n", 36526516Sbrian lqr->PeerInOctets, lqr->PeerOutLQRs); 36636285Sbrian log_Printf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n", 36726516Sbrian lqr->PeerOutPackets, lqr->PeerOutOctets); 3686059Samurai } 3696059Samurai} 37046686Sbrian 371131327Sbrianvoid 372131327Sbrianlqr_Analyse(const struct hdlc *hdlc, const struct lqrdata *oldlqr, 373131327Sbrian const struct lqrdata *newlqr) 374131327Sbrian{ 375131327Sbrian u_int32_t LQRs, transitLQRs, pkts, octets, disc, err; 376131327Sbrian 377131327Sbrian if (!newlqr->PeerInLQRs) /* No analysis possible yet! */ 378131327Sbrian return; 379131327Sbrian 380131327Sbrian log_Printf(LogLQM, "Analysis:\n"); 381131327Sbrian 382131327Sbrian LQRs = (newlqr->LastOutLQRs - oldlqr->LastOutLQRs) - 383131327Sbrian (newlqr->PeerInLQRs - oldlqr->PeerInLQRs); 384131327Sbrian transitLQRs = hdlc->lqm.lqr.OutLQRs - newlqr->LastOutLQRs; 385131327Sbrian pkts = (newlqr->LastOutPackets - oldlqr->LastOutPackets) - 386131327Sbrian (newlqr->PeerInPackets - oldlqr->PeerInPackets); 387131327Sbrian octets = (newlqr->LastOutOctets - oldlqr->LastOutOctets) - 388131327Sbrian (newlqr->PeerInOctets - oldlqr->PeerInOctets); 389131327Sbrian log_Printf(LogLQM, " Outbound lossage: %d LQR%s (%d en route), %d packet%s," 390131327Sbrian " %d octet%s\n", (int)LQRs, LQRs == 1 ? "" : "s", (int)transitLQRs, 391131327Sbrian (int)pkts, pkts == 1 ? "" : "s", 392131327Sbrian (int)octets, octets == 1 ? "" : "s"); 393131327Sbrian 394131327Sbrian pkts = (newlqr->PeerOutPackets - oldlqr->PeerOutPackets) - 395131327Sbrian (hdlc->lqm.lqr.Save.InPackets - hdlc->lqm.lqr.prevSave.InPackets); 396131327Sbrian octets = (newlqr->PeerOutOctets - oldlqr->PeerOutOctets) - 397131327Sbrian (hdlc->lqm.lqr.Save.InOctets - hdlc->lqm.lqr.prevSave.InOctets); 398131327Sbrian log_Printf(LogLQM, " Inbound lossage: %d packet%s, %d octet%s\n", 399131327Sbrian (int)pkts, pkts == 1 ? "" : "s", 400131327Sbrian (int)octets, octets == 1 ? "" : "s"); 401131327Sbrian 402131327Sbrian disc = newlqr->PeerInDiscards - oldlqr->PeerInDiscards; 403131327Sbrian err = newlqr->PeerInErrors - oldlqr->PeerInErrors; 404131327Sbrian if (disc && err) 405131327Sbrian log_Printf(LogLQM, " Likely due to both peer congestion" 406131327Sbrian " and physical errors\n"); 407131327Sbrian else if (disc) 408131327Sbrian log_Printf(LogLQM, " Likely due to peer congestion\n"); 409131327Sbrian else if (err) 410131327Sbrian log_Printf(LogLQM, " Likely due to physical errors\n"); 411131327Sbrian else if (pkts) 412131327Sbrian log_Printf(LogLQM, " Likely due to transport " 413131327Sbrian "congestion\n"); 414131327Sbrian} 415131327Sbrian 41646686Sbrianstatic struct mbuf * 417134789Sbrianlqr_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp, 418134789Sbrian int pri __unused, u_short *proto) 41946686Sbrian{ 42046686Sbrian struct physical *p = link2physical(l); 421230348Seadler int len, layer; 42246686Sbrian 42346686Sbrian if (!p) { 42446686Sbrian /* Oops - can't happen :-] */ 42554912Sbrian m_freem(bp); 42646686Sbrian return NULL; 42746686Sbrian } 42846686Sbrian 429131327Sbrian bp = m_pullup(bp); 430131327Sbrian len = m_length(bp); 431131327Sbrian 432131327Sbrian /*- 43346686Sbrian * From rfc1989: 43446686Sbrian * 43546686Sbrian * All octets which are included in the FCS calculation MUST be counted, 43646686Sbrian * including the packet header, the information field, and any padding. 43746686Sbrian * The FCS octets MUST also be counted, and one flag octet per frame 43846686Sbrian * MUST be counted. All other octets (such as additional flag 43946686Sbrian * sequences, and escape bits or octets) MUST NOT be counted. 44046686Sbrian * 441131327Sbrian * As we're stacked higher than the HDLC layer (otherwise HDLC wouldn't be 44246686Sbrian * able to calculate the FCS), we must not forget about these additional 44346686Sbrian * bytes when we're asynchronous. 44446686Sbrian * 445131327Sbrian * We're also expecting to be stacked *before* the likes of the proto and 446131327Sbrian * acf layers (to avoid alignment issues), so deal with this too. 44746686Sbrian */ 44846686Sbrian 449131327Sbrian p->hdlc.lqm.ifOutUniPackets++; 450131327Sbrian p->hdlc.lqm.ifOutOctets += len + 1; /* plus 1 flag octet! */ 451131327Sbrian for (layer = 0; layer < l->nlayers; layer++) 452131327Sbrian switch (l->layer[layer]->type) { 453131327Sbrian case LAYER_ACF: 454131327Sbrian p->hdlc.lqm.ifOutOctets += acf_WrapperOctets(&l->lcp, *proto); 455131327Sbrian break; 456131327Sbrian case LAYER_ASYNC: 457131327Sbrian /* Not included - see rfc1989 */ 458131327Sbrian break; 459131327Sbrian case LAYER_HDLC: 460134789Sbrian p->hdlc.lqm.ifOutOctets += hdlc_WrapperOctets(); 461131327Sbrian break; 462131327Sbrian case LAYER_LQR: 463131327Sbrian layer = l->nlayers; 464131327Sbrian break; 465131327Sbrian case LAYER_PROTO: 466131327Sbrian p->hdlc.lqm.ifOutOctets += proto_WrapperOctets(&l->lcp, *proto); 467131327Sbrian break; 468131327Sbrian case LAYER_SYNC: 469131327Sbrian /* Nothing to add on */ 470131327Sbrian break; 471131327Sbrian default: 472131327Sbrian log_Printf(LogWARN, "Oops, don't know how to do octets for %s layer\n", 473131327Sbrian l->layer[layer]->name); 474131327Sbrian break; 475131327Sbrian } 47646686Sbrian 47746686Sbrian if (*proto == PROTO_LQR) { 47847695Sbrian /* Overwrite the entire packet (created in SendLqrData()) */ 47946686Sbrian struct lqrdata lqr; 480131327Sbrian size_t pending_pkts, pending_octets; 48146686Sbrian 482131327Sbrian p->hdlc.lqm.lqr.OutLQRs++; 483131327Sbrian 484131327Sbrian /* 485131327Sbrian * We need to compensate for the fact that we're pushing our data 486131327Sbrian * onto the highest priority queue by factoring out packet & octet 487131327Sbrian * values from other queues! 488131327Sbrian */ 489131327Sbrian link_PendingLowPriorityData(l, &pending_pkts, &pending_octets); 490131327Sbrian 491131327Sbrian memset(&lqr, '\0', sizeof lqr); 49246686Sbrian lqr.MagicNumber = p->link.lcp.want_magic; 49346686Sbrian lqr.LastOutLQRs = p->hdlc.lqm.lqr.peer.PeerOutLQRs; 49446686Sbrian lqr.LastOutPackets = p->hdlc.lqm.lqr.peer.PeerOutPackets; 49546686Sbrian lqr.LastOutOctets = p->hdlc.lqm.lqr.peer.PeerOutOctets; 496131327Sbrian lqr.PeerInLQRs = p->hdlc.lqm.lqr.Save.InLQRs; 497131327Sbrian lqr.PeerInPackets = p->hdlc.lqm.lqr.Save.InPackets; 498131327Sbrian lqr.PeerInDiscards = p->hdlc.lqm.lqr.Save.InDiscards; 499131327Sbrian lqr.PeerInErrors = p->hdlc.lqm.lqr.Save.InErrors; 500131327Sbrian lqr.PeerInOctets = p->hdlc.lqm.lqr.Save.InOctets; 501131327Sbrian lqr.PeerOutLQRs = p->hdlc.lqm.lqr.OutLQRs; 502131327Sbrian lqr.PeerOutPackets = p->hdlc.lqm.ifOutUniPackets - pending_pkts; 503131327Sbrian /* Don't forget our ``flag'' octets.... */ 504131327Sbrian lqr.PeerOutOctets = p->hdlc.lqm.ifOutOctets - pending_octets - pending_pkts; 505131327Sbrian lqr_Dump(l->name, "Output", &lqr); 50646686Sbrian lqr_ChangeOrder(&lqr, (struct lqrdata *)MBUF_CTOP(bp)); 50746686Sbrian } 50846686Sbrian 50946686Sbrian return bp; 51046686Sbrian} 51146686Sbrian 51247695Sbrianstatic struct mbuf * 513134789Sbrianlqr_LayerPull(struct bundle *b __unused, struct link *l __unused, 514134789Sbrian struct mbuf *bp, u_short *proto) 51547695Sbrian{ 51647695Sbrian /* 517131327Sbrian * This is the ``Rx'' process from rfc1989, although a part of it is 518131327Sbrian * actually performed by sync_LayerPull() & hdlc_LayerPull() so that 519131327Sbrian * our octet counts are correct. 52047695Sbrian */ 521131327Sbrian 52247695Sbrian if (*proto == PROTO_LQR) 52354912Sbrian m_settype(bp, MB_LQRIN); 52447695Sbrian return bp; 52547695Sbrian} 52647695Sbrian 52746686Sbrian/* 52846686Sbrian * Statistics for pulled packets are recorded either in hdlc_PullPacket() 52946686Sbrian * or sync_PullPacket() 53046686Sbrian */ 53146686Sbrian 53247695Sbrianstruct layer lqrlayer = { LAYER_LQR, "lqr", lqr_LayerPush, lqr_LayerPull }; 533