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.6 1996/01/30 11:08:37 dfr 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 #include "main.h" 35 36 struct pppTimer LqrTimer; 37 38 static u_long lastpeerin = (u_long)-1; 39 40 static int lqmmethod; 41 static int echoseq; 42 static int gotseq; 43 static int lqrsendcnt; 44 45 struct echolqr { 46 u_long magic; 47 u_long signature; 48 u_long sequence; 49 }; 50 51 #define SIGNATURE 0x594e4f54 52 53 static void 54 SendEchoReq() 55 { 56 struct fsm *fp = &LcpFsm; 57 struct echolqr *lqr, lqrdata; 58 59 if (fp->state == ST_OPENED) { 60 lqr = &lqrdata; 61 lqr->magic = htonl(LcpInfo.want_magic); 62 lqr->signature = htonl(SIGNATURE); 63 LogPrintf(LOG_LQM_BIT, "Send echo LQR [%d]\n", echoseq); 64 lqr->sequence = htonl(echoseq++); 65 FsmOutput(fp, CODE_ECHOREQ, fp->reqid++, 66 (u_char *)lqr, sizeof(struct echolqr)); 67 } 68 } 69 70 void 71 RecvEchoLqr(bp) 72 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(LOG_LQM_BIT, "Got echo LQR [%d]\n", ntohl(lqr->sequence)); 82 gotseq = seq; 83 } 84 } 85 } 86 87 void 88 LqrChangeOrder(src, dst) 89 struct lqrdata *src, *dst; 90 { 91 u_long *sp, *dp; 92 int n; 93 94 sp = (u_long *)src; 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 * XXX: Should implement LQM strategy 110 */ 111 LogPrintf(LOG_PHASE_BIT, "** 1 Too many ECHO packets are lost. **\n"); 112 lqmmethod = 0; /* Prevent rcursion via LcpClose() */ 113 LcpClose(); 114 } else { 115 bp = mballoc(sizeof(struct lqrdata), MB_LQR); 116 HdlcOutput(PRI_LINK, PROTO_LQR, bp); 117 lqrsendcnt++; 118 } 119 } else if (lqmmethod & LQM_ECHO) { 120 if (echoseq - gotseq > 5) { 121 LogPrintf(LOG_PHASE_BIT, "** 2 Too many ECHO packets are lost. **\n"); 122 lqmmethod = 0; /* Prevent rcursion via LcpClose() */ 123 LcpClose(); 124 } else 125 SendEchoReq(); 126 } 127 128 if (lqmmethod && Enabled(ConfLqr)) 129 StartTimer(&LqrTimer); 130 } 131 132 void 133 LqrInput(struct mbuf *bp) 134 { 135 int len; 136 u_char *cp; 137 struct lqrdata *lqr; 138 139 len = plength(bp); 140 if (len != sizeof(struct lqrdata)) { 141 pfree(bp); 142 return; 143 } 144 145 if (!Acceptable(ConfLqr)) { 146 bp->offset -= 2; 147 bp->cnt += 2; 148 149 cp = MBUF_CTOP(bp); 150 LcpSendProtoRej(cp, bp->cnt); 151 } else { 152 cp = MBUF_CTOP(bp); 153 lqr = (struct lqrdata *)cp; 154 if (ntohl(lqr->MagicNumber) != LcpInfo.his_magic) { 155 #ifdef notdef 156 logprintf("*** magic %x != expecting %x\n", ntohl(lqr->MagicNumber), LcpInfo.his_magic); 157 #endif 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 171 * i) We are not running LQR timer. 172 * ii) Two successive LQR's PeerInLQRs are same. 173 */ 174 if (LqrTimer.load == 0 || lastpeerin == HisLqrData.PeerInLQRs) { 175 lqmmethod |= LQM_LQR; 176 SendLqrReport(); 177 } 178 lastpeerin = HisLqrData.PeerInLQRs; 179 } 180 pfree(bp); 181 } 182 183 /* 184 * When LCP is reached to opened state, We'll start LQM activity. 185 */ 186 void 187 StartLqm() 188 { 189 struct lcpstate *lcp = &LcpInfo; 190 int period; 191 192 lqmmethod = LQM_ECHO; 193 if (Enabled(ConfLqr)) 194 lqmmethod |= LQM_LQR; 195 StopTimer(&LqrTimer); 196 LogPrintf(LOG_LQM_BIT, "LQM method = %d\n", lqmmethod); 197 198 if (lcp->his_lqrperiod || lcp->want_lqrperiod) { 199 /* 200 * We need to run timer. Let's figure out period. 201 */ 202 period = lcp->his_lqrperiod ? lcp->his_lqrperiod : lcp->want_lqrperiod; 203 StopTimer(&LqrTimer); 204 LqrTimer.state = TIMER_STOPPED; 205 LqrTimer.load = period * SECTICKS / 100; 206 LqrTimer.func = SendLqrReport; 207 SendLqrReport(); 208 StartTimer(&LqrTimer); 209 LogPrintf(LOG_LQM_BIT, "Will send LQR every %d.%d secs\n", 210 period/100, period % 100); 211 } else { 212 LogPrintf(LOG_LQM_BIT, "LQR is not activated.\n"); 213 } 214 } 215 216 void 217 StopLqrTimer(void) 218 { 219 StopTimer(&LqrTimer); 220 } 221 222 void 223 StopLqr(method) 224 int method; 225 { 226 LogPrintf(LOG_LQM_BIT, "StopLqr method = %x\n", method); 227 228 if (method == LQM_LQR) 229 LogPrintf(LOG_LQM_BIT, "Stop sending LQR, Use LCP ECHO instead.\n"); 230 if (method == LQM_ECHO) 231 LogPrintf(LOG_LQM_BIT, "Stop sending LCP ECHO.\n"); 232 lqmmethod &= ~method; 233 if (lqmmethod) 234 SendLqrReport(); 235 else 236 StopTimer(&LqrTimer); 237 } 238 239 void 240 LqrDump(message, lqr) 241 char *message; 242 struct lqrdata *lqr; 243 { 244 if (loglevel & (1 << LOG_LQM)) { 245 LogTimeStamp(); 246 logprintf("%s:\n", message); 247 LogTimeStamp(); 248 logprintf(" Magic: %08x LastOutLQRs: %08x\n", 249 lqr->MagicNumber, lqr->LastOutLQRs); 250 LogTimeStamp(); 251 logprintf(" LastOutPackets: %08x LastOutOctets: %08x\n", 252 lqr->LastOutPackets, lqr->LastOutOctets); 253 LogTimeStamp(); 254 logprintf(" PeerInLQRs: %08x PeerInPackets: %08x\n", 255 lqr->PeerInLQRs, lqr->PeerInPackets); 256 LogTimeStamp(); 257 logprintf(" PeerInDiscards: %08x PeerInErrors: %08x\n", 258 lqr->PeerInDiscards, lqr->PeerInErrors); 259 LogTimeStamp(); 260 logprintf(" PeerInOctets: %08x PeerOutLQRs: %08x\n", 261 lqr->PeerInOctets, lqr->PeerOutLQRs); 262 LogTimeStamp(); 263 logprintf(" PeerOutPackets: %08x PeerOutOctets: %08x\n", 264 lqr->PeerOutPackets, lqr->PeerOutOctets); 265 } 266 } 267