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.15 1997/06/09 03:27:27 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(bp) 73 struct mbuf *bp; 74 { 75 struct echolqr *lqr; 76 u_long seq; 77 78 if (plength(bp) == sizeof(struct echolqr)) { 79 lqr = (struct echolqr *)MBUF_CTOP(bp); 80 if (htonl(lqr->signature) == SIGNATURE) { 81 seq = ntohl(lqr->sequence); 82 LogPrintf(LogLQM, "Got echo LQR [%d]\n", ntohl(lqr->sequence)); 83 gotseq = seq; 84 } 85 } 86 } 87 88 void 89 LqrChangeOrder(src, dst) 90 struct lqrdata *src, *dst; 91 { 92 u_long *sp, *dp; 93 int n; 94 95 sp = (u_long *)src; dp = (u_long *)dst; 96 for (n = 0; n < sizeof(struct lqrdata)/sizeof(u_long); n++) 97 *dp++ = ntohl(*sp++); 98 } 99 100 static void 101 SendLqrReport() 102 { 103 struct mbuf *bp; 104 105 StopTimer(&LqrTimer); 106 107 if (lqmmethod & LQM_LQR) { 108 if (lqrsendcnt > 5) { 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 131 if (lqmmethod && Enabled(ConfLqr)) 132 StartTimer(&LqrTimer); 133 } 134 135 void 136 LqrInput(struct mbuf *bp) 137 { 138 int len; 139 u_char *cp; 140 struct lqrdata *lqr; 141 142 len = plength(bp); 143 if (len != sizeof(struct lqrdata)) { 144 pfree(bp); 145 return; 146 } 147 148 if (!Acceptable(ConfLqr)) { 149 bp->offset -= 2; 150 bp->cnt += 2; 151 152 cp = MBUF_CTOP(bp); 153 LcpSendProtoRej(cp, bp->cnt); 154 } else { 155 cp = MBUF_CTOP(bp); 156 lqr = (struct lqrdata *)cp; 157 if (ntohl(lqr->MagicNumber) != LcpInfo.his_magic) { 158 LogPrintf(LogERROR, "LqrInput: magic %x != expecting %x\n", 159 ntohl(lqr->MagicNumber), LcpInfo.his_magic); 160 pfree(bp); 161 return; 162 } 163 164 /* 165 * Convert byte order and save into our strage 166 */ 167 LqrChangeOrder(lqr, &HisLqrData); 168 LqrDump("LqrInput", &HisLqrData); 169 lqrsendcnt = 0; /* we have received LQR from peer */ 170 171 /* 172 * Generate LQR responce to peer, if 173 * i) We are not running LQR timer. 174 * ii) Two successive LQR's PeerInLQRs are same. 175 */ 176 if (LqrTimer.load == 0 || lastpeerin == HisLqrData.PeerInLQRs) { 177 lqmmethod |= LQM_LQR; 178 SendLqrReport(); 179 } 180 lastpeerin = HisLqrData.PeerInLQRs; 181 } 182 pfree(bp); 183 } 184 185 /* 186 * When LCP is reached to opened state, We'll start LQM activity. 187 */ 188 void 189 StartLqm() 190 { 191 struct lcpstate *lcp = &LcpInfo; 192 int period; 193 194 lqrsendcnt = 0; /* start waiting all over for ECHOs */ 195 echoseq = 0; 196 gotseq = 0; 197 198 lqmmethod = LQM_ECHO; 199 if (Enabled(ConfLqr)) 200 lqmmethod |= LQM_LQR; 201 StopTimer(&LqrTimer); 202 LogPrintf(LogLQM, "LQM method = %d\n", lqmmethod); 203 204 if (lcp->his_lqrperiod || lcp->want_lqrperiod) { 205 /* 206 * We need to run timer. Let's figure out period. 207 */ 208 period = lcp->his_lqrperiod ? lcp->his_lqrperiod : lcp->want_lqrperiod; 209 StopTimer(&LqrTimer); 210 LqrTimer.state = TIMER_STOPPED; 211 LqrTimer.load = period * SECTICKS / 100; 212 LqrTimer.func = SendLqrReport; 213 SendLqrReport(); 214 StartTimer(&LqrTimer); 215 LogPrintf(LogLQM, "Will send LQR every %d.%d secs\n", 216 period/100, period % 100); 217 } else { 218 LogPrintf(LogLQM, "LQR is not activated.\n"); 219 } 220 } 221 222 void 223 StopLqrTimer(void) 224 { 225 StopTimer(&LqrTimer); 226 } 227 228 void 229 StopLqr(method) 230 int method; 231 { 232 LogPrintf(LogLQM, "StopLqr method = %x\n", method); 233 234 if (method == LQM_LQR) 235 LogPrintf(LogLQM, "Stop sending LQR, Use LCP ECHO instead.\n"); 236 if (method == LQM_ECHO) 237 LogPrintf(LogLQM, "Stop sending LCP ECHO.\n"); 238 lqmmethod &= ~method; 239 if (lqmmethod) 240 SendLqrReport(); 241 else 242 StopTimer(&LqrTimer); 243 } 244 245 void 246 LqrDump(message, lqr) 247 char *message; 248 struct lqrdata *lqr; 249 { 250 if (LogIsKept(LogLQM)) { 251 LogPrintf(LogLQM, "%s:", message); 252 LogPrintf(LogLQM, " Magic: %08x LastOutLQRs: %08x\n", 253 lqr->MagicNumber, lqr->LastOutLQRs); 254 LogPrintf(LogLQM, " LastOutPackets: %08x LastOutOctets: %08x\n", 255 lqr->LastOutPackets, lqr->LastOutOctets); 256 LogPrintf(LogLQM, " PeerInLQRs: %08x PeerInPackets: %08x\n", 257 lqr->PeerInLQRs, lqr->PeerInPackets); 258 LogPrintf(LogLQM, " PeerInDiscards: %08x PeerInErrors: %08x\n", 259 lqr->PeerInDiscards, lqr->PeerInErrors); 260 LogPrintf(LogLQM, " PeerInOctets: %08x PeerOutLQRs: %08x\n", 261 lqr->PeerInOctets, lqr->PeerOutLQRs); 262 LogPrintf(LogLQM, " PeerOutPackets: %08x PeerOutOctets: %08x\n", 263 lqr->PeerOutPackets, lqr->PeerOutOctets); 264 } 265 } 266