1 /* 2 * PPP Line Quality Monitoring (LQM) Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: lqr.c,v 1.17 1997/08/25 00:29:18 brian Exp $ 21 * 22 * o LQR based on RFC1333 23 * 24 * TODO: 25 * o LQM policy 26 * o Allow user to configure LQM method and interval. 27 */ 28 #include "fsm.h" 29 #include "lcpproto.h" 30 #include "lqr.h" 31 #include "hdlc.h" 32 #include "lcp.h" 33 #include "loadalias.h" 34 #include "vars.h" 35 #include "main.h" 36 37 struct pppTimer LqrTimer; 38 39 static u_long lastpeerin = (u_long) - 1; 40 41 static int lqmmethod; 42 static int echoseq; 43 static int gotseq; 44 static int lqrsendcnt; 45 46 struct echolqr { 47 u_long magic; 48 u_long signature; 49 u_long sequence; 50 }; 51 52 #define SIGNATURE 0x594e4f54 53 54 static void 55 SendEchoReq() 56 { 57 struct fsm *fp = &LcpFsm; 58 struct echolqr *lqr, lqrdata; 59 60 if (fp->state == ST_OPENED) { 61 lqr = &lqrdata; 62 lqr->magic = htonl(LcpInfo.want_magic); 63 lqr->signature = htonl(SIGNATURE); 64 LogPrintf(LogLQM, "Send echo LQR [%d]\n", echoseq); 65 lqr->sequence = htonl(echoseq++); 66 FsmOutput(fp, CODE_ECHOREQ, fp->reqid++, 67 (u_char *) lqr, sizeof(struct echolqr)); 68 } 69 } 70 71 void 72 RecvEchoLqr(struct mbuf * bp) 73 { 74 struct echolqr *lqr; 75 u_long seq; 76 77 if (plength(bp) == sizeof(struct echolqr)) { 78 lqr = (struct echolqr *) MBUF_CTOP(bp); 79 if (htonl(lqr->signature) == SIGNATURE) { 80 seq = ntohl(lqr->sequence); 81 LogPrintf(LogLQM, "Got echo LQR [%d]\n", ntohl(lqr->sequence)); 82 gotseq = seq; 83 } 84 } 85 } 86 87 void 88 LqrChangeOrder(struct lqrdata * src, struct lqrdata * dst) 89 { 90 u_long *sp, *dp; 91 int n; 92 93 sp = (u_long *) src; 94 dp = (u_long *) dst; 95 for (n = 0; n < sizeof(struct lqrdata) / sizeof(u_long); n++) 96 *dp++ = ntohl(*sp++); 97 } 98 99 static void 100 SendLqrReport() 101 { 102 struct mbuf *bp; 103 104 StopTimer(&LqrTimer); 105 106 if (lqmmethod & LQM_LQR) { 107 if (lqrsendcnt > 5) { 108 109 /* 110 * XXX: Should implement LQM strategy 111 */ 112 LogPrintf(LogPHASE, "** 1 Too many ECHO packets are lost. **\n"); 113 lqmmethod = 0; /* Prevent rcursion via LcpClose() */ 114 reconnect(RECON_TRUE); 115 LcpClose(); 116 } else { 117 bp = mballoc(sizeof(struct lqrdata), MB_LQR); 118 HdlcOutput(PRI_LINK, PROTO_LQR, bp); 119 lqrsendcnt++; 120 } 121 } else if (lqmmethod & LQM_ECHO) { 122 if (echoseq - gotseq > 5) { 123 LogPrintf(LogPHASE, "** 2 Too many ECHO packets are lost. **\n"); 124 lqmmethod = 0; /* Prevent rcursion via LcpClose() */ 125 reconnect(RECON_TRUE); 126 LcpClose(); 127 } else 128 SendEchoReq(); 129 } 130 if (lqmmethod && Enabled(ConfLqr)) 131 StartTimer(&LqrTimer); 132 } 133 134 void 135 LqrInput(struct mbuf * bp) 136 { 137 int len; 138 u_char *cp; 139 struct lqrdata *lqr; 140 141 len = plength(bp); 142 if (len != sizeof(struct lqrdata)) { 143 pfree(bp); 144 return; 145 } 146 if (!Acceptable(ConfLqr)) { 147 bp->offset -= 2; 148 bp->cnt += 2; 149 150 cp = MBUF_CTOP(bp); 151 LcpSendProtoRej(cp, bp->cnt); 152 } else { 153 cp = MBUF_CTOP(bp); 154 lqr = (struct lqrdata *) cp; 155 if (ntohl(lqr->MagicNumber) != LcpInfo.his_magic) { 156 LogPrintf(LogERROR, "LqrInput: magic %x != expecting %x\n", 157 ntohl(lqr->MagicNumber), LcpInfo.his_magic); 158 pfree(bp); 159 return; 160 } 161 162 /* 163 * Convert byte order and save into our strage 164 */ 165 LqrChangeOrder(lqr, &HisLqrData); 166 LqrDump("LqrInput", &HisLqrData); 167 lqrsendcnt = 0; /* we have received LQR from peer */ 168 169 /* 170 * Generate LQR responce to peer, if i) We are not running LQR timer. ii) 171 * Two successive LQR's PeerInLQRs are same. 172 */ 173 if (LqrTimer.load == 0 || lastpeerin == HisLqrData.PeerInLQRs) { 174 lqmmethod |= LQM_LQR; 175 SendLqrReport(); 176 } 177 lastpeerin = HisLqrData.PeerInLQRs; 178 } 179 pfree(bp); 180 } 181 182 /* 183 * When LCP is reached to opened state, We'll start LQM activity. 184 */ 185 void 186 StartLqm() 187 { 188 struct lcpstate *lcp = &LcpInfo; 189 int period; 190 191 lqrsendcnt = 0; /* start waiting all over for ECHOs */ 192 echoseq = 0; 193 gotseq = 0; 194 195 lqmmethod = LQM_ECHO; 196 if (Enabled(ConfLqr)) 197 lqmmethod |= LQM_LQR; 198 StopTimer(&LqrTimer); 199 LogPrintf(LogLQM, "LQM method = %d\n", lqmmethod); 200 201 if (lcp->his_lqrperiod || lcp->want_lqrperiod) { 202 203 /* 204 * We need to run timer. Let's figure out period. 205 */ 206 period = lcp->his_lqrperiod ? lcp->his_lqrperiod : lcp->want_lqrperiod; 207 StopTimer(&LqrTimer); 208 LqrTimer.state = TIMER_STOPPED; 209 LqrTimer.load = period * SECTICKS / 100; 210 LqrTimer.func = SendLqrReport; 211 SendLqrReport(); 212 StartTimer(&LqrTimer); 213 LogPrintf(LogLQM, "Will send LQR every %d.%d secs\n", 214 period / 100, period % 100); 215 } else { 216 LogPrintf(LogLQM, "LQR is not activated.\n"); 217 } 218 } 219 220 void 221 StopLqrTimer() 222 { 223 StopTimer(&LqrTimer); 224 } 225 226 void 227 StopLqr(int method) 228 { 229 LogPrintf(LogLQM, "StopLqr method = %x\n", method); 230 231 if (method == LQM_LQR) 232 LogPrintf(LogLQM, "Stop sending LQR, Use LCP ECHO instead.\n"); 233 if (method == LQM_ECHO) 234 LogPrintf(LogLQM, "Stop sending LCP ECHO.\n"); 235 lqmmethod &= ~method; 236 if (lqmmethod) 237 SendLqrReport(); 238 else 239 StopTimer(&LqrTimer); 240 } 241 242 void 243 LqrDump(char *message, struct lqrdata * lqr) 244 { 245 if (LogIsKept(LogLQM)) { 246 LogPrintf(LogLQM, "%s:\n", message); 247 LogPrintf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n", 248 lqr->MagicNumber, lqr->LastOutLQRs); 249 LogPrintf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n", 250 lqr->LastOutPackets, lqr->LastOutOctets); 251 LogPrintf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n", 252 lqr->PeerInLQRs, lqr->PeerInPackets); 253 LogPrintf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n", 254 lqr->PeerInDiscards, lqr->PeerInErrors); 255 LogPrintf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n", 256 lqr->PeerInOctets, lqr->PeerOutLQRs); 257 LogPrintf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n", 258 lqr->PeerOutPackets, lqr->PeerOutOctets); 259 } 260 } 261