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