xref: /freebsd/usr.sbin/ppp/lqr.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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