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