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.3 1995/04/17 04:21:35 amurai 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 "vars.h" 34 35 struct pppTimer LqrTimer; 36 37 static u_long lastpeerin = (u_long)-1; 38 39 static int lqmmethod; 40 static int echoseq; 41 static int gotseq; 42 static int lqrsendcnt; 43 44 struct echolqr { 45 u_long magic; 46 u_long signature; 47 u_long sequence; 48 }; 49 50 #define SIGNATURE 0x594e4f54 51 52 static void 53 SendEchoReq() 54 { 55 struct fsm *fp = &LcpFsm; 56 struct echolqr *lqr, lqrdata; 57 58 if (fp->state == ST_OPENED) { 59 lqr = &lqrdata; 60 lqr->magic = htonl(LcpInfo.want_magic); 61 lqr->signature = htonl(SIGNATURE); 62 LogPrintf(LOG_LQM, "Send echo LQR [%d]\n", echoseq); 63 lqr->sequence = htonl(echoseq++); 64 FsmOutput(fp, CODE_ECHOREQ, fp->reqid++, 65 (u_char *)lqr, sizeof(struct echolqr)); 66 } 67 } 68 69 void 70 RecvEchoLqr(bp) 71 struct mbuf *bp; 72 { 73 struct echolqr *lqr; 74 u_long seq; 75 76 if (plength(bp) == sizeof(struct echolqr)) { 77 lqr = (struct echolqr *)MBUF_CTOP(bp); 78 if (htonl(lqr->signature) == SIGNATURE) { 79 seq = ntohl(lqr->sequence); 80 LogPrintf(LOG_LQM, "Got echo LQR [%d]\n", ntohl(lqr->sequence)); 81 gotseq = seq; 82 } 83 } 84 } 85 86 void 87 LqrChangeOrder(src, dst) 88 struct lqrdata *src, *dst; 89 { 90 u_long *sp, *dp; 91 int n; 92 93 sp = (u_long *)src; dp = (u_long *)dst; 94 for (n = 0; n < sizeof(struct lqrdata)/sizeof(u_long); n++) 95 *dp++ = ntohl(*sp++); 96 } 97 98 static void 99 SendLqrReport() 100 { 101 struct mbuf *bp; 102 103 StopTimer(&LqrTimer); 104 105 if (lqmmethod & LQM_LQR) { 106 if (lqrsendcnt > 5) { 107 /* 108 * XXX: Should implement LQM strategy 109 */ 110 LogPrintf(LOG_PHASE, "** Too many ECHO packets are lost. **\n"); 111 LcpClose(); 112 Cleanup(EX_ERRDEAD); 113 } else { 114 bp = mballoc(sizeof(struct lqrdata), MB_LQR); 115 HdlcOutput(PRI_URGENT, PROTO_LQR, bp); 116 lqrsendcnt++; 117 } 118 } else if (lqmmethod & LQM_ECHO) { 119 if (echoseq - gotseq > 5) { 120 LogPrintf(LOG_PHASE, "** Too many ECHO packets are lost. **\n"); 121 LcpClose(); 122 Cleanup(EX_ERRDEAD); 123 } else 124 SendEchoReq(); 125 } 126 127 if (lqmmethod && Enabled(ConfLqr)) 128 StartTimer(&LqrTimer); 129 } 130 131 void 132 LqrInput(struct mbuf *bp) 133 { 134 int len; 135 u_char *cp; 136 struct lqrdata *lqr; 137 138 len = plength(bp); 139 if (len != sizeof(struct lqrdata)) { 140 pfree(bp); 141 return; 142 } 143 144 if (!Acceptable(ConfLqr)) { 145 bp->offset -= 2; 146 bp->cnt += 2; 147 148 cp = MBUF_CTOP(bp); 149 LcpSendProtoRej(cp, bp->cnt); 150 } else { 151 cp = MBUF_CTOP(bp); 152 lqr = (struct lqrdata *)cp; 153 if (ntohl(lqr->MagicNumber) != LcpInfo.his_magic) { 154 #ifdef notdef 155 logprintf("*** magic %x != expecting %x\n", ntohl(lqr->MagicNumber), LcpInfo.his_magic); 156 #endif 157 pfree(bp); 158 return; 159 } 160 161 /* 162 * Convert byte order and save into our strage 163 */ 164 LqrChangeOrder(lqr, &HisLqrData); 165 LqrDump("LqrInput", &HisLqrData); 166 lqrsendcnt = 0; /* we have received LQR from peer */ 167 168 /* 169 * Generate LQR responce to peer, if 170 * i) We are not running LQR timer. 171 * ii) 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 lqmmethod = LQM_ECHO; 192 if (Enabled(ConfLqr)) 193 lqmmethod |= LQM_LQR; 194 StopTimer(&LqrTimer); 195 LogPrintf(LOG_LQM, "LQM method = %d\n", lqmmethod); 196 197 if (lcp->his_lqrperiod || lcp->want_lqrperiod) { 198 /* 199 * We need to run timer. Let's figure out period. 200 */ 201 period = lcp->his_lqrperiod ? lcp->his_lqrperiod : lcp->want_lqrperiod; 202 StopTimer(&LqrTimer); 203 LqrTimer.state = TIMER_STOPPED; 204 LqrTimer.load = period * SECTICKS / 100; 205 LqrTimer.func = SendLqrReport; 206 SendLqrReport(); 207 StartTimer(&LqrTimer); 208 LogPrintf(LOG_LQM, "Will send LQR every %d.%d secs\n", 209 period/100, period % 100); 210 } else { 211 LogPrintf(LOG_LQM, "LQR is not activated.\n"); 212 } 213 } 214 215 void 216 StopLqr(method) 217 int method; 218 { 219 LogPrintf(LOG_LQM, "StopLqr method = %x\n", method); 220 221 if (method == LQM_LQR) 222 LogPrintf(LOG_LQM, "Stop sending LQR, Use LCP ECHO instead.\n"); 223 if (method == LQM_ECHO) 224 LogPrintf(LOG_LQM, "Stop sending LCP ECHO.\n"); 225 lqmmethod &= ~method; 226 if (lqmmethod) 227 SendLqrReport(); 228 else 229 StopTimer(&LqrTimer); 230 } 231 232 void 233 LqrDump(message, lqr) 234 char *message; 235 struct lqrdata *lqr; 236 { 237 if (loglevel & (1 << LOG_LQM)) { 238 LogTimeStamp(); 239 logprintf("%s:\n", message); 240 LogTimeStamp(); 241 logprintf(" Magic: %08x LastOutLQRs: %08x\n", 242 lqr->MagicNumber, lqr->LastOutLQRs); 243 LogTimeStamp(); 244 logprintf(" LastOutPackets: %08x LastOutOctets: %08x\n", 245 lqr->LastOutPackets, lqr->LastOutOctets); 246 LogTimeStamp(); 247 logprintf(" PeerInLQRs: %08x PeerInPackets: %08x\n", 248 lqr->PeerInLQRs, lqr->PeerInPackets); 249 LogTimeStamp(); 250 logprintf(" PeerInDiscards: %08x PeerInErrors: %08x\n", 251 lqr->PeerInDiscards, lqr->PeerInErrors); 252 LogTimeStamp(); 253 logprintf(" PeerInOctets: %08x PeerOutLQRs: %08x\n", 254 lqr->PeerInOctets, lqr->PeerOutLQRs); 255 LogTimeStamp(); 256 logprintf(" PeerOutPackets: %08x PeerOutOctets: %08x\n", 257 lqr->PeerOutPackets, lqr->PeerOutOctets); 258 } 259 } 260