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